Jaro similarity: Difference between revisions

Add C# implementation
(Add C# implementation)
 
(53 intermediate revisions by 26 users not shown)
Line 1:
{{task}}
 
The Jaro distance is a measure of edit distance between two strings; its inverse, called the ''Jaro similarity'', is a measure of two strings' similarity: the higher the value, the more similar the strings are. The score is normalized such that   '''0'''   equates to no similarities and   '''1'''   is an exact match.
The Jaro distance is a measure of similarity between two strings.
 
The higher the Jaro distance for two strings is, the more similar the strings are.
 
The score is normalized such that   '''0'''   equates to no similarity and   '''1'''   is an exact match.
 
 
;;Definition
 
The Jaro distancesimilarity &nbsp; <math>d_j</math> &nbsp; of two given strings &nbsp; <math>s_1</math> &nbsp; and &nbsp; <math>s_2</math> &nbsp; is
 
: <math>d_j = \left\{
Line 24 ⟶ 20:
 
 
Two characters from &nbsp; <math>s_1</math> &nbsp; and &nbsp; <math>s_2</math> &nbsp; respectively, are considered ''matching'' only if they are the same and not farther apart than &nbsp; <math>\left\lfloor\frac{\max(|s_1|,|s_2|)}{2}\right\rfloor-1</math> characters.
 
Each character of &nbsp; <math>s_1</math> &nbsp; is compared with all its matching characters in &nbsp; <math>s_2</math>. Each difference in position is half a ''transposition''; that is, the number of transpositions is half the number of characters which are common to the two strings but occupy different positions in each one.
characters in &nbsp; <math>s_2</math>.
 
The number of matching (but different sequence order) characters
divided by 2 defines the number of ''transpositions''.
 
 
Line 50 ⟶ 42:
;Task
 
Implement the Jaro-distance algorithm and show the distancessimilarity scores for each of the following pairs:
 
* ("MARTHA", "MARHTA")
Line 60 ⟶ 52:
* [[wp:Jaro-Winkler_distance|Jaro–Winkler distance]] on Wikipedia.
<br><br>
 
=={{header|11l}}==
{{trans|Python}}
 
<syntaxhighlight lang="11l">F jaro(s, t)
V s_len = s.len
V t_len = t.len
 
I s_len == 0 & t_len == 0
R 1.0
 
V match_distance = (max(s_len, t_len) I/ 2) - 1
V s_matches = [0B] * s_len
V t_matches = [0B] * t_len
V matches = 0
V transpositions = 0
 
L(i) 0 .< s_len
V start = max(0, i - match_distance)
V end = min(i + match_distance + 1, t_len)
 
L(j) start .< end
I t_matches[j]
L.continue
I s[i] != t[j]
L.continue
s_matches[i] = 1B
t_matches[j] = 1B
matches++
L.break
 
I matches == 0
R 0.0
 
V k = 0
L(i) 0 .< s_len
I !s_matches[i]
L.continue
L !t_matches[k]
k++
I s[i] != t[k]
transpositions++
k++
 
R ((Float(matches) / s_len) +
(Float(matches) / t_len) +
((matches - transpositions / 2) / matches)) / 3
 
L(s, t) [(‘MARTHA’, ‘MARHTA’),
(‘DIXON’, ‘DICKSONX’),
(‘JELLYFISH’, ‘SMELLYFISH’)]
print(‘jaro('#.', '#.') = #.10’.format(s, t, jaro(s, t)))</syntaxhighlight>
 
{{out}}
<pre>
jaro('MARTHA', 'MARHTA') = 0.9444444444
jaro('DIXON', 'DICKSONX') = 0.7666666667
jaro('JELLYFISH', 'SMELLYFISH') = 0.8962962963
</pre>
 
=={{header|Action!}}==
<syntaxhighlight lang="action">
DEFINE STRING="CHAR ARRAY" ; sys.act
DEFINE ASCII_SpaceBar="32"
 
INT FUNC JaroDistance(STRING str1, str2)
STRING Z(15)
INT S1, S2, J, M, N, L, I, K, skip, Max, Min
INT Result
Result=0
S1=str1(0)
S2=str2(0)
IF S1>S2 THEN
SCopy(Z,str1)
SCopy(str1,str2)
SCopy(str2,Z)
M=S1
S1=S2
S2=M
FI
J=1 M=0 N=0 L=S2/2 SCopy(Z,str2)
FOR I=1 TO S1 DO
skip=0
IF str1(I)=str2(J) THEN
M==+1
str2(J)=ASCII_SpaceBar
skip=1
FI
IF skip=0 THEN
Max=1
IF Max<(I-L) THEN Max=I-L FI
Min=S2
IF Min>(I+L-1) THEN Min=I+L-1 FI
FOR K=Max TO Min DO
IF str1(I)=str2(K) THEN
N==+1
M==+1
str2(K)=ASCII_SpaceBar
IF K>J THEN J=K FI
FI
OD
FI
IF J<S2 THEN J==+1 FI
OD
IF M=0 THEN
Result=0 ; Jaro distance
ELSE
N=N/2
Result=((M*100)/S1+(M*100)/S2+(((M-N)*100)/M))/3 ; Jaro distance
FI
; Min=S1 IF Min>S2 THEN Min=S2 FI
; M=Min IF M>3 THEN M=3 FI
; M==+1 L=0 SCopy(str2,Z)
; IF M>Min THEN M=Min FI
; FOR I=1 TO M DO
; IF str1(I)=str2(I) THEN
; L==+1
; ELSE
; EXIT
; FI
; OD
; Result=Result*100 + (((L*100)/10)*(100 - Result)) ; Jaro Winkler distance
; Result=(Result+49)/100
RETURN(Result)
 
PROC MAIN()
INT result
STRING Word_1(15), Word_2(15)
PUT(125)
PUTE()
 
SCopy(Word_1,"LIGITA") SCopy(Word_2,"LIGA")
PrintF("%S - %S%E",Word_1,Word_2)
result=JaroDistance(Word_1,Word_2)
PrintF("Jaro Distance=%U%E%E",result)
 
SCopy(Word_1,"ZEILANE") SCopy(Word_2,"ZEIDONE")
PrintF("%S - %S%E",Word_1,Word_2)
result=JaroDistance(Word_1,Word_2)
PrintF("Jaro Distance=%U%E%E",result)
 
SCopy(Word_1,"JELLYFISH") SCopy(Word_2,"SMELLYFISH")
PrintF("%S - %S%E",Word_1,Word_2)
result=JaroDistance(Word_1,Word_2)
PrintF("Jaro Distance=%U%E%E",result)
RETURN
</syntaxhighlight>
{{out}}
<pre>MARTHA, MARHTA: 94
DIXON, DICKSONX: 76
JELLYFISH, SMELLYFISH: 89
</pre>
 
=={{header|Ada}}==
<syntaxhighlight lang="ada">with Ada.Text_IO;
 
procedure Jaro_Distances is
 
type Jaro_Measure is new Float;
 
function Jaro_Distance (Left, Right : in String) return Jaro_Measure
is
Left_Matches : array (Left'Range) of Boolean := (others => False);
Right_Matches : array (Right'Range) of Boolean := (others => False);
Matches : Natural := 0;
Transpositions : Natural := 0;
begin
if Left'Length = 0 and Right'Length = 0 then
return 1.000;
end if;
 
declare
Match_Distance : constant Natural := Natural'Max (Left'Length, Right'Length) / 2 - 1;
begin
for L in Left'Range loop
declare
First : constant Natural := Natural'Max (Right'First, Right'First + L - Left'First - Match_Distance);
Last : constant Natural := Natural'Min (L - Left'First + Match_Distance + Right'First, Right'Last);
begin
for R in First .. Last loop
if
not Right_Matches (R) and
Left (L) = Right (R)
then
Left_Matches (L) := True;
Right_Matches (R) := True;
Matches := Matches + 1;
exit;
end if;
end loop;
end;
end loop;
end;
 
if Matches = 0 then
return 0.000;
end if;
 
declare
R : Natural := Right'First;
begin
for L in Left'Range loop
if Left_Matches (L) then
while not Right_Matches (R) loop
R := R + 1;
end loop;
if Left (L) /= Right (R) then
Transpositions := Transpositions + 1;
end if;
R := R + 1;
end if;
end loop;
end;
 
declare
Match : constant Float := Float (Matches);
Term_1 : constant Float := Match / Float (Left'Length);
Term_2 : constant Float := Match / Float (Right'Length);
Term_3 : constant Float := (Match - Float (Transpositions) / 2.0) / Match;
begin
return Jaro_Measure ((Term_1 + Term_2 + Term_3) / 3.0);
end;
end Jaro_Distance;
 
procedure Show_Jaro (Left, Right : in String)
is
package Jaro_IO is
new Ada.Text_IO.Float_IO (Jaro_Measure);
use Ada.Text_IO;
 
Distance : constant Jaro_Measure := Jaro_Distance (Left, Right);
begin
Jaro_IO.Put (Distance, Fore => 1, Aft => 5, Exp => 0);
Set_Col (10); Put (Left);
Set_Col (22); Put (Right);
New_Line;
end Show_Jaro;
 
S1 : constant String := " MARTHA VS MARHTA ";
begin
Show_Jaro ("DWAYNE", "DUANE");
Show_Jaro ("DIXON", "DICKSONX");
Show_Jaro ("JELLYFISH", "SMELLYFISH");
Show_Jaro (S1 (3 .. 8), S1 (13 .. 18));
end Jaro_Distances;</syntaxhighlight>
 
{{out}}
<pre>0.82222 DWAYNE DUANE
0.76667 DIXON DICKSONX
0.89630 JELLYFISH SMELLYFISH
0.94444 MARTHA MARHTA</pre>
 
=={{header|ARM Assembly}}==
{{works with|as|Raspberry Pi}}
<syntaxhighlight lang="arm assembly">
<lang ARM Assembly>
 
/* ARM assembly Raspberry PI */
Line 416 ⟶ 660:
 
 
</syntaxhighlight>
</lang>
 
=={{header|Arturo}}==
 
<syntaxhighlight lang="rebol">loop [
["MARTHA" "MARHTA"]
["DIXON" "DICKSONX"]
["JELLYFISH" "SMELLYFISH"]
] 'pair ->
print [pair "-> Jaro similarity:" round.to: 3 jaro first pair last pair]</syntaxhighlight>
 
{{out}}
 
<pre>[MARTHA MARHTA] -> Jaro similarity: 0.944
[DIXON DICKSONX] -> Jaro similarity: 0.767
[JELLYFISH SMELLYFISH] -> Jaro similarity: 0.896</pre>
 
=={{header|AWK}}==
<syntaxhighlight lang="awk">
<lang AWK>
# syntax: GAWK -f JARO_DISTANCE.AWK
BEGIN {
Line 471 ⟶ 731:
function max(x,y) { return((x > y) ? x : y) }
function min(x,y) { return((x < y) ? x : y) }
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 479 ⟶ 739:
0.8962963 'JELLYFISH' 'SMELLYFISH'
</pre>
 
=={{header|BBC BASIC}}==
{{works with|BBC BASIC for Windows}}
<syntaxhighlight lang="bbcbasic"> PRINT "Jaro similarity between the two strings:"
PROCDescribeJaro("MARTHA", "MARHTA")
PROCDescribeJaro("DIXON", "DICKSONX")
PROCDescribeJaro("JELLYFISH", "SMELLYFISH")
PROCDescribeJaro("DWAYNE", "DUANE")
PROCDescribeJaro("a", "b")
PROCDescribeJaro("", "")
END
 
DEF FNMax(a, b)=(a + b + ABS(a - b)) / 2
DEF FNMin(a, b)=(a + b - ABS(a - b)) / 2
 
DEF PROCDescribeJaro(word1$, word2$)
LOCAL d%, i%, j%, k%, l1%, l2%, m%, t%
 
PRINT " '" word1$ "' and '" word2$ "'" TAB(30) "= ";
IF word1$ == "" IF word2$ == "" PRINT;1 : ENDPROC
l1%=LENword1$
l2%=LENword2$
IF l1% < l2% SWAP l1%, l2% SWAP word1$, word2$
 
d%=l1% / 2 - 1
j%=1
FOR i%=1 TO l2%
IF MID$(word2$, i%, 1) == MID$(word1$, j%, 1) THEN
m%+=1
MID$(word1$, j%)=" "
ELSE
FOR k%=FNMax(1, i% - d%) TO FNMin(l1%, i% + d%)
IF MID$(word2$, i%, 1) == MID$(word1$, k%, 1) THEN
t%+=1
m%+=1
MID$(word1$, k%)=" "
IF k% > j% j%=k%
ENDIF
NEXT
ENDIF
j%+=1
NEXT
IF m% == 0 THEN
PRINT;0
ELSE
PRINT;(m% / l2% + m% / l1% + ((m% - (t% >> 1)) / m%)) / 3
ENDIF
ENDPROC</syntaxhighlight>
{{out}}
<pre>Jaro similarity between the two strings:
'MARTHA' and 'MARHTA' = 0.944444444
'DIXON' and 'DICKSONX' = 0.766666667
'JELLYFISH' and 'SMELLYFISH' = 0.896296296
'DWAYNE' and 'DUANE' = 0.822222222
'a' and 'b' = 0
'' and '' = 1</pre>
 
=={{header|C}}==
<langsyntaxhighlight Clang="c">#include <stdlib.h>
#include <string.h>
#include <ctype.h>
Line 569 ⟶ 886:
printf("%f\n", jaro("DIXON", "DICKSONX"));
printf("%f\n", jaro("JELLYFISH", "SMELLYFISH"));
}</langsyntaxhighlight>
{{out}}
<pre>
Line 575 ⟶ 892:
0.766667
0.896296
</pre>
 
=={{header|C#}}==
{{trans|Java}}
<syntaxhighlight lang="C#">
using System;
 
public class JaroDistance {
public static double Jaro(string s, string t) {
int s_len = s.Length;
int t_len = t.Length;
 
if (s_len == 0 && t_len == 0) return 1;
 
int match_distance = Math.Max(s_len, t_len) / 2 - 1;
 
bool[] s_matches = new bool[s_len];
bool[] t_matches = new bool[t_len];
 
int matches = 0;
int transpositions = 0;
 
for (int i = 0; i < s_len; i++) {
int start = Math.Max(0, i - match_distance);
int end = Math.Min(i + match_distance + 1, t_len);
 
for (int j = start; j < end; j++) {
if (t_matches[j]) continue;
if (s[i] != t[j]) continue;
s_matches[i] = true;
t_matches[j] = true;
matches++;
break;
}
}
 
if (matches == 0) return 0;
 
int k = 0;
for (int i = 0; i < s_len; i++) {
if (!s_matches[i]) continue;
while (!t_matches[k]) k++;
if (s[i] != t[k]) transpositions++;
k++;
}
 
return (((double)matches / s_len) +
((double)matches / t_len) +
(((double)matches - transpositions / 2.0) / matches)) / 3.0;
}
 
public static void Main(string[] args) {
Console.WriteLine(Jaro("MARTHA", "MARHTA"));
Console.WriteLine(Jaro("DIXON", "DICKSONX"));
Console.WriteLine(Jaro("JELLYFISH", "SMELLYFISH"));
}
}
</syntaxhighlight>
{{out}}
<pre>
0.944444444444445
0.766666666666667
0.896296296296296
 
</pre>
 
=={{header|C++}}==
{{trans|C}}
<langsyntaxhighlight lang="cpp">#include <algorithm>
#include <iostream>
#include <string>
Line 627 ⟶ 1,008:
cout << jaro("JELLYFISH", "SMELLYFISH") << endl;
return 0;
}</langsyntaxhighlight>
 
=={{header|Clojure}}==
<langsyntaxhighlight lang="clojure">
(ns test-project-intellij.core
(:gen-class))
Line 712 ⟶ 1,093:
(println (jaro "DIXON" "DICKSONX"))
(println (jaro "JELLYFISH" "SMELLYFISH"))
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 718 ⟶ 1,099:
0.76666665
0.8962963
</pre>
 
=={{header|CLU}}==
{{trans|C}}
<syntaxhighlight lang="clu">max = proc [T: type] (a, b: T) returns (T)
where T has lt: proctype (T,T) returns (bool)
if a<b then return(b) else return(a) end
end max
 
min = proc [T: type] (a, b: T) returns (T)
where T has lt: proctype (T,T) returns (bool)
if a<b then return(a) else return(b) end
end min
 
jaro = proc (s1, s2: string) returns (real)
s1_len: int := string$size(s1)
s2_len: int := string$size(s2)
if s1_len = 0 & s2_len = 0 then return(1.0)
elseif s1_len = 0 | s2_len = 0 then return(0.0)
end
 
dist: int := max[int](s1_len, s2_len)/2 - 1
s1_match: array[bool] := array[bool]$fill(1,s1_len,false)
s2_match: array[bool] := array[bool]$fill(1,s2_len,false)
 
matches: real := 0.0
transpositions: real := 0.0
for i: int in int$from_to(1, s1_len) do
start: int := max[int](1, i-dist)
end_: int := min[int](i+dist, s2_len)
for k: int in int$from_to(start, end_) do
if s2_match[k] then continue end
if s1[i] ~= s2[k] then continue end
s1_match[i] := true
s2_match[k] := true
matches := matches + 1.0
break
end
end
 
if matches=0.0 then return(0.0) end
k: int := 1
for i: int in int$from_to(1, s1_len) do
if ~s1_match[i] then continue end
while ~s2_match[k] do k := k + 1 end
if s1[i] ~= s2[k] then
transpositions := transpositions + 1.0
end
k := k+1
end
 
transpositions := transpositions / 2.0
return( ((matches / real$i2r(s1_len)) +
(matches / real$i2r(s2_len)) +
((matches - transpositions) / matches)) / 3.0)
end jaro
 
start_up = proc ()
po: stream := stream$primary_output()
stream$putl(po, f_form(jaro("MARTHA", "MARHTA"), 1, 6))
stream$putl(po, f_form(jaro("DIXON", "DICKSONX"), 1, 6))
stream$putl(po, f_form(jaro("JELLYFISH", "SMELLYFISH"), 1, 6))
end start_up</syntaxhighlight>
{{out}}
<pre>0.944444
0.766667
0.896296</pre>
 
=={{header|COBOL}}==
{{trans|Java}}
<syntaxhighlight lang="cobol">
identification division.
program-id. JaroDistance.
environment division.
configuration section.
repository.
function length intrinsic
function trim intrinsic
function max intrinsic
function min intrinsic
.
data division.
working-storage section.
77 s pic x(255).
77 t pic x(255).
77 s-length pic 9(3).
77 t-length pic 9(3).
77 i pic 9(3).
77 j pic 9(3).
77 k pic 9(3).
77 start-pos pic 9(3).
77 end-pos pic 9(3).
77 match-distance pic 9(3).
77 matches pic 9(3).
77 transpositions pic 9(3).
77 distance pic 9v9(8).
01 jaro-table.
05 filler occurs 255.
10 filler pic 9(1).
88 s-matches value 1 when set to false is 0.
10 filler pic 9(1).
88 t-matches value 1 when set to false is 0.
 
procedure division.
main.
move "MARTHA" to s
move "MARHTA" to t
perform jaro-calc-and-show
move "DIXON" to s
move "DICKSONX" to t
perform jaro-calc-and-show
move "JELLYFISH" to s
move "SMELLYFISH" to t
perform jaro-calc-and-show
stop run
.
jaro-calc-and-show.
perform jaro-distance
display trim(s) " -> " trim(t) ", distance=" distance
.
jaro-distance.
move length(trim(s)) to s-length
move length(trim(t)) to t-length
if s-length = zeros and t-length = zeros
move 1 to distance
exit paragraph
end-if
 
compute match-distance = max(s-length, t-length) / 2 - 1
move low-values to jaro-table
move zeros to matches
move zeros to transpositions
perform varying i from 1 by 1 until i > s-length
move max(1, i - match-distance) to start-pos
move min(i + match-distance, t-length) to end-pos
perform varying j from start-pos by 1 until j > end-pos
if t-matches(j) or s(i:1) <> t(j:1)
exit perform cycle
end-if,
set s-matches(i), t-matches(j) to true
add 1 to matches
exit perform
end-perform
end-perform
if matches = zeros
move matches to distance
exit paragraph
end-if
 
move 1 to k
perform varying i from 1 by 1 until i > s-length
if not s-matches(i)
exit perform cycle
end-if
perform until t-matches(k)
add 1 to k
end-perform
if s(i:1) <> t(k:1)
add 1 to transpositions
end-if
add 1 to k
end-perform
 
compute distance = ((matches / s-length) + (matches / t-length) +
((matches - transpositions / 2) / matches)) / 3
.
</syntaxhighlight>
{{out}}
<pre>
MARTHA -> MARHTA, distance=0.94444444
DIXON -> DICKSONX, distance=0.76666666
JELLYFISH -> SMELLYFISH, distance=0.89629629
</pre>
 
=={{header|CoffeeScript}}==
{{trans|C++}}
<langsyntaxhighlight lang="coffeescript">jaro = (s1, s2) ->
l1 = s1.length
l2 = s2.length
Line 751 ⟶ 1,309:
console.log jaro "MARTHA", "MARHTA"
console.log jaro "DIXON", "DICKSONX"
console.log jaro "JELLYFISH", "SMELLYFISH"</langsyntaxhighlight>
{{Out}}
<pre>0.9444444444444445
Line 759 ⟶ 1,317:
=={{header|Crystal}}==
{{trans|Ruby}}
<langsyntaxhighlight lang="ruby">def jaro(s, t)
return 1.0 if s == t
s_len = s.size
t_len = t.size
match_distance = ({s_len, t_len}.max // 2) - 1
 
s_matches = Array.new(s_len, false)
Line 803 ⟶ 1,361:
JELLYFISH SMELLYFISH
).each_slice(2) { |(s ,t)| puts "jaro(#{s}, #{t}) = #{"%.10f" % jaro(s, t)}" }
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 813 ⟶ 1,371:
=={{header|D}}==
{{trans|Kotlin}}
<langsyntaxhighlight Dlang="d">auto jaro(in string s1, in string s2) {
int s1_len = cast(int) s1.length;
int s2_len = cast(int) s2.length;
Line 852 ⟶ 1,410:
writeln(jaro( "DIXON", "DICKSONX"));
writeln(jaro("JELLYFISH", "SMELLYFISH"));
}</langsyntaxhighlight>
<pre>0.944444
0.766667
0.896296</pre>
 
=={{header|Delphi}}==
See [https://rosettacode.org/wiki/Jaro_distance#Pascal Pascal].
 
=={{header|Elixir}}==
{{trans|Ruby}}
{{works with|Elixir|1.3}}
<langsyntaxhighlight lang="elixir">defmodule Jaro do
def distance(s, t) when is_binary(s) and is_binary(t), do:
distance(to_charlist(s), to_charlist(t))
Line 917 ⟶ 1,478:
|> Enum.each(fn [s,t] ->
:io.format "jaro(~s, ~s) = ~.10f~n", [inspect(s), inspect(t), Jaro.distance(s, t)]
end)</langsyntaxhighlight>
 
{{out}}
Line 928 ⟶ 1,489:
Elixir has a built-in function (<code>String.jaro_distance</code>).
 
=={{header|Emacs Lisp}}==
{{trans|Python}}
<syntaxhighlight lang="lisp">
(let ()
(defun jaro (s1 s2)
(let (mw mflags1 mflags2 fn-reset-mflags fn-reset-all-mflags fn-cnt-trans)
(setq mflags1 (make-vector (length s1) nil))
(setq mflags2 (make-vector (length s2) nil))
(setq mw (1- (/ (max (length s1) (length s2)) 2)))
(setq fn-reset-mflags
(lambda (idx)
(let ((start (max 0 (- idx mw)))
(end (min (1- (length s2)) (+ idx mw))))
(cl-loop for i from start to end do
(when (and (not (elt mflags1 idx))
(not (elt mflags2 i)))
(when (equal (elt s1 idx) (elt s2 i))
(aset mflags1 idx 't)
(aset mflags2 i 't) ) ) ) ) ) )
(setq fn-reset-all-mflags
(lambda ()
(dotimes (idx (length s1))
(funcall fn-reset-mflags idx) ) ) )
(setq fn-cnt-trans
(lambda ()
(let ((cur2 0) (transposition 0))
(dotimes (cur1 (length s1))
(when (aref mflags1 cur1)
(while (not (aref mflags2 cur2))
(setq cur2 (1+ cur2)) )
(when (not (equal (aref s1 cur1)
(aref s2 cur2)))
(setq transposition (1+ transposition)) )
(setq cur2 (1+ cur2))
)
)
transposition ) ) )
(funcall fn-reset-all-mflags)
(let ((m (seq-count (lambda (f) f) mflags1))
(tr (funcall fn-cnt-trans)))
;;(message "matches: %s, transposition: %s, |s1|: %d |s2|: %d" m tr (length s1) (length s2))
(if (= m 0)
0
(progn (/ (+ (/ (float m) (length s1)) (/ (float m) (length s2)) (/ (float (- m (/ (float tr) 2))) m) ) 3))
) ) ) )
 
(let ((params '(("MARTHA" "MARHTA")
("DIXON" "DICKSONX")
("JELLYFISH" "SMELLYFISH"))))
(dolist (p params)
(message "jaro(%s, %s) = %f"
(nth 0 p) (nth 1 p)
(jaro (nth 0 p) (nth 1 p)))
)
)
)
 
</syntaxhighlight>
 
{{out}}
<pre>
jaro(MARTHA, MARHTA) = 0.944444
jaro(DIXON, DICKSONX) = 0.766667
jaro(JELLYFISH, SMELLYFISH) = 0.896296
</pre>
 
=={{header|F_Sharp|F#}}==
<syntaxhighlight lang="fsharp">
// Calculate Jaro distance of 2 strings. Nigel Galloway: August 7th., 2020
let fG n g=Seq.map2(fun n g->if g=1 then Some n else None) n g |> Seq.choose id
let J (n:string) (g:string)=
let s1,s2=n.Length,g.Length
let w,m1,m2=(max s1 s2)/2-1,Array.zeroCreate<int>s1,Array.zeroCreate<int>s2
g|>Seq.iteri(fun i g->match [max(i-w) 0..min(i+w)(s1-1)]|>Seq.tryFind(fun i->n.[i]=g&&m1.[i]=0) with Some n->m1.[n]<-1;m2.[i]<-1 |_->())
let t=float(Seq.fold2(fun Σ n g->Σ + (if n<>g then 1 else 0)) 0 (fG n m1) (fG g m2))/2.0
let m=float(m2|>Array.sum) in if m=0.0 then m else ((m/float s1)+(m/float s2)+((m-t)/m))/3.0
 
printfn "MARTHA MARHTA->%f" (J "MARTHA" "MARHTA")
printfn "DIXON DICKSONX->%f" (J "DIXON" "DICKSONX")
printfn "JELLYFISH SMELLYFISH->%f" (J "JELLYFISH" "SMELLYFISH")
</syntaxhighlight>
{{out}}
<pre>
MARTHA MARHTA->0.944444
DIXON DICKSONX->0.766667
JELLYFISH SMELLYFISH->0.896296
</pre>
=={{header|Factor}}==
{{works with|Factor|0.99 development release 2019-03-17+}}
<langsyntaxhighlight lang="factor">USING: formatting fry generalizations kernel locals make math
math.order sequences sequences.extras ;
IN: rosetta-code.jaro-distance
Line 963 ⟶ 1,613:
] 2 4 mnapply ;
 
MAIN: jaro-demo</langsyntaxhighlight>
{{out}}
<pre>
Line 973 ⟶ 1,623:
 
=={{header|FreeBASIC}}==
<langsyntaxhighlight lang="freebasic">' version 09-10-2016
' compile with: fbc -s console
 
Line 1,029 ⟶ 1,679:
Print : Print "hit any key to end program"
Sleep
End</langsyntaxhighlight>
{{out}}
<pre> jaro (MARTHA, MARHTA) = 0.9444444444444444
Line 1,036 ⟶ 1,686:
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package main
 
import "fmt"
Line 1,104 ⟶ 1,754:
fmt.Printf("%f\n", jaro("DIXON", "DICKSONX"))
fmt.Printf("%f\n", jaro("JELLYFISH", "SMELLYFISH"))
}</langsyntaxhighlight>
{{out}}
<pre>
Line 1,113 ⟶ 1,763:
 
=={{header|Haskell}}==
<langsyntaxhighlight Haskelllang="haskell">import Data.List (sortBy, elemIndex, intercalate, sortOn)
import Data.Ord (comparing)
import Text.Printf (printf)
import Data.Maybe (mapMaybe)
import Text.Printf (printf)
 
---------------------- JARO DISTANCE ---------------------
 
jaro :: Ord a => [a] -> [a] -> Float
jaro x y =
let| f0 == (fromIntegralm .= length)0
| otherwise =
[m, t] = [f, fromIntegral . transpositions] <*> [matches x y]
(1 / 3)
[s1, s2] = [f] <*> [x, y]
* ( (m / s1) + (m / s2) + ((m - t) / m))
in case m of
where
0 -> 0
f = fromIntegral . length
_ -> (1 / 3) * ((m / s1) + (m / s2) + ((m - t) / m))
[m, t] =
[f, fromIntegral . transpositions]
<*> [matches x y]
[s1, s2] = [f] <*> [x, y]
 
matches :: Eq a => [a] -> [a] -> [(Int, a)]
matches s1 s2 =
let [(l1, xs), (l2, ys)] =
sortOn
sortBy (comparing fst) ((length >>= (,)) <$> [s1, s2])
fst
((length >>= (,)) <$> [s1, s2])
r = quot l2 2 - 1
in mapMaybe
( \(c, n) ->
-- Initial chars out of range ?
 
->
let offset = max 0 (n - (r + 1))
in -- Any offset for this char within range.
in elemIndex c (drop offset (take (n + r) ys)) >>=
>>= (\i -> Just (offset + i, c)))
(zip xs [1 ..])
(zip xs [1 ..])
 
transpositions :: Ord a => [(Int, a)] -> Int
transpositions = length . filter (uncurry (>)) . (zip <*> tail)
length
. filter (uncurry (>))
. (zip <*> tail)
 
-- TEST --------------------------------------------- TEST -------------------------
main :: IO ()
main =
mapM_ putStrLn $
fmap
(\(s1, s2) -> intercalate " -> " [s1, s2, printf "%.3f\n" $ jaro s1 s2]) <$>
[ ("DWAYNE" \(s1, "DUANE"s2) ->
intercalate
, ("MARTHA", "MARHTA")
, ("DIXON", "DICKSONX -> ")
[s1, s2, printf "%.3f\n" $ jaro s1 s2]
, ("JELLYFISH", "SMELLYFISH")
)
]</lang>
[ ("DWAYNE", "DUANE"),
("MARTHA", "MARHTA"),
("DIXON", "DICKSONX"),
("JELLYFISH", "SMELLYFISH")
]</syntaxhighlight>
{{Out}}
<pre>DWAYNE -> DUANE -> 0.822
Line 1,167 ⟶ 1,833:
{{trans|Kotlin}}
{{works with|Neko|2.1.0}}
<langsyntaxhighlight Haxelang="haxe">class Jaro {
private static function jaro(s1: String, s2: String): Float {
var s1_len = s1.length;
Line 1,205 ⟶ 1,871:
Sys.println(jaro("JELLYFISH", "SMELLYFISH"));
}
}</langsyntaxhighlight>
{{Out}}
<pre>0.944444444444445
0.766666666666667
0.896296296296296</pre>
 
=={{header|IS-BASIC}}==
<syntaxhighlight lang="is-basic">100 PROGRAM "Jaro.bas"
110 DO
120 READ IF MISSING EXIT DO:A$,B$
130 PRINT A$;", ";B$;":";JARO(A$,B$)
140 LOOP
150 DEF JARO(A$,B$)
160 LET J=1:LET M,T,JARO=0:LET S1=LEN(A$):LET S2=LEN(B$)
170 IF S1>S2 THEN
180 LET Z$=A$:LET A$=B$:LET B$=Z$
190 LET Z=S1:LET S1=S2:LET S2=Z
200 END IF
210 LET MAXDIST=INT(S2/2)
220 FOR I=1 TO S1
230 IF A$(I)=B$(J) THEN
240 LET M=M+1:CALL CHANGE(B$," ",J)
250 ELSE
260 FOR K=MAX(1,I-MAXDIST) TO MIN(S2,I+MAXDIST)
270 IF A$(I)=B$(K) THEN
280 LET T=T+1:LET M=M+1:CALL CHANGE(B$," ",K)
290 IF K>J THEN LET J=K
300 END IF
310 NEXT
320 END IF
330 IF J<S2 THEN LET J=J+1
340 NEXT
350 IF M<>0 THEN
360 LET T=INT(T/2)
370 LET JARO=(M/S1+M/S2+((M-T)/M))/3
380 END IF
390 END DEF
400 DEF CHANGE(REF S$,C$,POS)
410 LET S$=S$(:POS-1)&C$&S$(POS+1:)
420 END DEF
430 DATA MARTHA,MARHTA
440 DATA DIXON,DICKSONX
450 DATA JELLYFISH,SMELLYFISH
460 DATA DWAYNE,DUANE</syntaxhighlight>
 
=={{header|J}}==
Line 1,215 ⟶ 1,920:
Implementation:
 
<langsyntaxhighlight Jlang="j">jaro=: dyad define
d=. ((x >.&# y)%2)-1
e=. (x =/y) * d >: |x -/&(i.@#) y
Line 1,225 ⟶ 1,930:
s2=. #y
((m%s1)+(m%s2)+(m-t)%m)%3
)</langsyntaxhighlight>
 
Task examples:
 
<langsyntaxhighlight Jlang="j"> 'MARTHA' jaro 'MARHTA'
0.944444
'DIXON' jaro 'DICKSONX'
0.766667
'JELLYFISH' jaro 'SMELLYFISH'
0.896296</langsyntaxhighlight>
 
=={{header|Java}}==
<langsyntaxhighlight lang="java">public class JaroDistance {
public static double jaro(String s, String t) {
int s_len = s.length();
Line 1,286 ⟶ 1,991:
System.out.println(jaro("JELLYFISH", "SMELLYFISH"));
}
}</langsyntaxhighlight>
{{out}}
<pre>
Line 1,293 ⟶ 1,998:
0.8962962962962964
</pre>
 
=={{header|jq}}==
{{trans|Wren}}
{{works with|jq}}
def jaro(s1; s2):
'''Works with gojq, the Go implementation of jq'''
<syntaxhighlight lang="jq">def jaro($s1; $s2):
def when(p; q): if p then q else . end;
($s1|length) as $le1
| (s1$s2|length) as $len1le2
| if |$le1 (s2|length)== as0 and $len2le2 == 0 then 1
|elif (( [$len1,le1 $len2]== |0 max )or /$le2 2== -0 1)then as $match_standard0
else ((((if $le2 > $le1 then $le2 else $le1 end) / 2) | floor) - 1) as $dist
| {m:0, p:0}
| {matches: 0, matches2: [], matches2: [], transpos: 0 }
| reduce range(0; $len1) as $l1
| reduce range(.0; s1[$l1:$l1+1]le1) as $t1i (.;
(($i - $dist) | reduceif . < range(0; $len2 then 0 else . end) as $l2start
| (($i + $dist + 1) | if (.; s2[> $l2:le2 then $l2+1]le2 else . end) as $t2stop
| when(.k $t1 == $t2;start
| until(.k >= $stop;
when( ($l2-$l1) <= $match_standard and ($l1-$l2) <= $match_standard;
if (.matches2[.k] or $s1[$i:$i+1] != $s2[.mk:.k+=1]) |not
then | when(.matches1[$l2i] == $l1; .p += 1) ) ) )true
| ((.m-matches2[.p)/2)k] as= $ttrue
| ( (.m/$len1) + (.m/$len2) + (( | .m-$t)/.m)matches ) /+= 31
; | .k = $stop
else .k += 1
end) )
jaro("MARTHA";"MARHTA")
| if .matches == 0 then 0
, jaro("DIXON"; "DICKSONX")
else .k = 0
, jaro("JELLYFISH";"SMELLYFISH")
| reduce range(0; $le1) as $i (.;
if .matches1[$i]
then until(.k >= $le2 or .matches2[.k]; .k += 1)
| if .k < $le2 and ($s1[$i:$i+1] != $s2[.k:.k+1]) then .transpos += 1 else . end
| .k += 1
else .
end )
| .transpos /= 2
| (.matches/$le1 + .matches/$le2 + ((.matches - .transpos)/.matches)) / 3
end
end ;
 
def task:
Output:
[["MARTHA","MARHTA"],
["DIXON", "DICKSONX"],
["JELLYFISH","SMELLYFISH"],
["ABC","DEF"]][]
| (jaro(.[0]; .[1]) * 1000 | floor / 1000) as $d
| "jaro(\(.[0]); \(.[1])) => \($d)";
 
task</syntaxhighlight>
{{out}}
<pre>
jaro(MARTHA; MARHTA) => 0.944
0.9444444444444444
jaro(DIXON; DICKSONX) => 0.766
0.6833333333333332
jaro(JELLYFISH; SMELLYFISH) => 0.896
0.8870370370370371
jaro(ABC; DEF) => 0
</pre>
 
=={{header|Julia}}==
{{works with|Julia|01.65}}
<langsyntaxhighlight lang="julia">function jarodistance(s1::AbstractString, s2::AbstractString)
m = t = p = l1 = l2 = 0
matchstd = max(length(s1), length(s2)) / 2 - 1
for i(i1, c1) in enumerate(s1[1:end])
l1for +=(i2, 1c2) in enumerate(s2)
(c1 == c2) && (abs(i2 - i1) ≤ matchstd) && (m += 1)
l2 = 0
for j in s2[ (c1 == c2) && (i2 == i1) && (p += 1:end])
l2 += 1
if i == j
if abs(l2 - l1) ≤ matchstd m += 1 end
if l2 == l1 p += 1 end
end
end
end
t = (m - p) / 2
d = 1 / 3 * (m / length(s1) + m / length(s2) + (m - t) / m)
return d
end
 
@show jarodistance("MARTHA", "MARHTA")
const testcouples = (("MARTHA", "MARHTA"), ("DIXON", "DICKSONX"), ("JELLYFISH", "SMELLYFISH"))
@show jarodistance("DIXON", "DICKSONX")
for (s1, s2) in testcouples
@show println("jarodistance(\"$s1\JELLYFISH", \"$s2\SMELLYFISH") = ", @sprintf "%2.2f" jarodistance(s1, s2))
</syntaxhighlight>
end</lang>
 
{{out}}
<pre>
<pre>jarodistance("MARTHA", "MARHTA") = 0.94
jarodistance("DIXONMARTHA", "DICKSONXMARHTA") = 0.689444444444444444
jarodistance("JELLYFISHDIXON", "SMELLYFISHDICKSONX") = 0.89</pre>6833333333333332
jarodistance("JELLYFISH", "SMELLYFISH") = 0.8870370370370371
</pre>
 
=={{header|Kotlin}}==
{{trans|Java}}
<langsyntaxhighlight lang="scala">object Jaro {
fun distance(s1: String, s2: String): Double {
val s1_len = s1.length
Line 1,395 ⟶ 2,118:
println(Jaro.distance("DIXON", "DICKSONX"))
println(Jaro.distance("JELLYFISH", "SMELLYFISH"))
}</langsyntaxhighlight>
 
=={{header|Mathematica}} / {{header|Wolfram Language}}==
<syntaxhighlight lang="mathematica">ClearAll[JaroDistance]
JaroDistance[s_String, t_String] := Module[{slen, tlen, maxdistance, smatches, tmatches, matches, transpositions, start, end, k, schar, tchar},
slen = StringLength[s];
tlen = StringLength[t];
schar = Characters[s];
tchar = Characters[t];
If[slen == tlen == 0,
1
,
maxdistance = Floor[Max[slen, tlen]/2] - 1;
smatches = ConstantArray[False, slen];
tmatches = ConstantArray[False, tlen];
matches = transpositions = 0;
Do[
start = Max[0, i - maxdistance];
end = Min[i + maxdistance + 1, tlen];
start = Max[1, i - maxdistance];
end = Min[i + maxdistance + 1, tlen];
Do[
If[! tmatches[[j]],
If[schar[[i]] == tchar[[j]],
smatches[[i]] = True;
tmatches[[j]] = True;
matches++;
Break[];
]
]
,
{j, start, end}
]
,
{i, slen}
];
If[matches == 0,
0
,
k = 1;
Do[
If[smatches[[i]],
While[! tmatches[[k]],
k++;
];
If[schar[[i]] != tchar[[k]],
transpositions++;
];
k++;
]
,
{i, slen}
];
N@(matches/slen + matches/tlen + (matches - transpositions/2)/matches)/3
]
]
]
JaroDistance["DWAYNE", "DUANE"]
JaroDistance["MARTHA", "MARHTA"]
JaroDistance["DIXON", "DICKSONX"]
JaroDistance["JELLYFISH", "SMELLYFISH"]</syntaxhighlight>
{{out}}
<pre>0.822222
0.944444
0.766667
0.896296</pre>
 
=={{header|Nim}}==
{{trans|Kotlin}}
<syntaxhighlight lang="nim">import lenientops
 
func jaro(s1, s2: string): float =
 
if s1.len == 0 and s2.len == 0: return 1
if s1.len == 0 or s2.len == 0: return 0
 
let matchDistance = max(s1.len, s2.len) div 2 - 1
var s1Matches = newSeq[bool](s1.len)
var s2Matches = newSeq[bool](s2.len)
var matches = 0
for i in 0..s1.high:
for j in max(0, i - matchDistance)..min(i + matchDistance, s2.high):
if not s2Matches[j] and s1[i] == s2[j]:
s1Matches[i] = true
s2Matches[j] = true
inc matches
break
if matches == 0: return 0
 
var transpositions = 0.0
var k = 0
for i in ..s1.high:
if not s1Matches[i]: continue
while not s2Matches[k]: inc k
if s1[i] != s2[k]: transpositions += 0.5
inc k
 
result = (matches / s1.len + matches / s2.len + (matches - transpositions) / matches) / 3
 
echo jaro("MARTHA", "MARHTA")
echo jaro("DIXON", "DICKSONX")
echo jaro("JELLYFISH", "SMELLYFISH")</syntaxhighlight>
 
{{out}}
<pre>0.9444444444444445
0.7666666666666666
0.8962962962962964</pre>
 
=={{header|Objeck}}==
{{trans|Java}}
<langsyntaxhighlight lang="objeck">class JaroDistance {
function : Main(args : String[]) ~ Nil {
Jaro("MARTHA", "MARHTA")->PrintLine();
Line 1,448 ⟶ 2,278:
((matches->As(Float) - transpositions/2.0) / matches)) / 3.0;
}
}</langsyntaxhighlight>
 
{{output}}
Line 1,462 ⟶ 2,292:
{{Works with|PARI/GP|2.7.4 and above}}
 
<langsyntaxhighlight lang="parigp">
\\Jaro distance between 2 strings s1 and s2.
\\ 4/12/16 aev
Line 1,498 ⟶ 2,328:
jaroDist("DWAYNE","DUANE");
}
</langsyntaxhighlight>
 
{{Output}}
Line 1,510 ⟶ 2,340:
 
=={{header|Pascal}}==
<langsyntaxhighlight lang="pascal">
program Jaro_distance;
 
uses SysUtils, Math;
 
//converted from C source by /u/bleuge
function ssJaroWinkler(s1, s2: string): double;
var
l1, l2, match_distance, matches, i, k, trans: integer;
bs1, bs2: array[1..255] of boolean; //used to avoid getmem, max string length is 255
begin
l1 := length(s1);
l2 := length(s2);
fillchar(bs1, sizeof(bs1), 0); //set booleans to false
fillchar(bs2, sizeof(bs2), 0);
if l1 = 0 then
if l2 = 0 then exit(1)
else exit(01);
else
match_distance:=(max(l1,l2) div 2)-1;
matches:= exit(0);
match_distance := (max(l1, l2) div 2) - 1;
trans:=0;
matches := 0;
trans := 0;
for i := 1 to l1 do
begin
for k := max(1, i - match_distance) to min(i + match_distance, l2) do
begin
if bs2[k] then continue;
if s1[i]<>s2[k] then continue;
bs1if s1[i]:=true; <> s2[k] then
bs2[k]:=true continue;
bs1[i] := true;
bs2[k] := true;
inc(matches);
break;
end;
end;
if matches = 0 then exit(0);
k:=1 exit(0);
k := 1;
for i := 1 to l1 do
begin
if (bs1[i] = false) then continue;
continue;
while (bs2[k]=false) do inc(k);
ifwhile s1[i]<>s2(bs2[k] then= inc(transfalse); do
inc(k);
if s1[i] <> s2[k] then
inc(trans);
inc(k);
end;
trans := trans div 2;
result := ((matches / l1) + (matches / l2) + ((matches - trans) / matches)) / 3;
end;
 
begin
//test
writeln(formatfloat('0.######', ssJaroWinkler('DWAYNE', 'DUANE')));
writeln(formatfloat('0.######', ssJaroWinkler('MARTHA', 'MARHTA')));
writeln(formatfloat('0.######', ssJaroWinkler('DIXON', 'DICKSONX')));
writeln(formatfloat('0.######', ssJaroWinkler('JELLYFISH', 'SMELLYFISH')));
{$IFNDEF LINUX}readln;{$ENDIF}
</lang>
end.</syntaxhighlight>
{{out}}
<pre>
Line 1,566 ⟶ 2,411:
 
=={{header|Perl}}==
<syntaxhighlight lang ="perl">use List::Util qw(min max)strict;
use warnings;
use List::Util qw(min max);
 
sub jaro {
my ($s, $t) = @_;
my(@s_matches, @t_matches, $matches);
 
myreturn $s_len1 =if length($s) eq $t;
my $t_len = length($t);
 
return 1 if $s_len == 0 and $t_len == 0;
 
my $match_distance = int(max($s_len, $t_len) / 2) - 1;
 
my @s_matches;
my @t_matches;
 
my @s = split(//, $s);
my @t = split(//, $t);
 
my ($matchess_len, @s) = 0(length $s, split //, $s);
foreach my ($it_len, @t) = (0length ..$t, split //, $#st) {;
 
my $match_distance = int (max($s_len, $t_len) / 2) - 1;
for my $i (0 .. $#s) {
my $start = max(0, $i - $match_distance);
my $end = min($i + $match_distance + 1, $t_len);
for my $j ($start .. $end - 1) {
 
foreach my $j ($start ..next if $endt_matches[$j] -or 1)$s[$i] {ne $t[$j];
($s_matches[$i], $t_matches[$j]) = and(1, next1);
$s[$i]matches++ eqand $t[$j] or nextlast;
$s_matches[$i] = 1;
$t_matches[$j] = 1;
$matches++;
last;
}
}
return 0 unless $matches;
 
return 0 ifmy($k, $matchestranspositions) == (0, 0);
for my $i (0 .. $#s) {
 
my $k next unless = 0$s_matches[$i];
$k++ until $t_matches[$k];
my $transpositions = 0;
$transpositions++ if $s[$i] ne $t[$k];
 
foreach my $i (0 .. $#s) {k++;
$s_matches[$i] or next;
until ($t_matches[$k]) { ++$k }
$s[$i] eq $t[$k] or ++$transpositions;
++$k;
}
( $matches/$s_len + $matches/$t_len + (($matches - $transpositions/2) / $matches) ) / 3;
 
(($matches / $s_len) + ($matches / $t_len) +
(($matches - $transpositions / 2) / $matches)) / 3;
}
 
printf( "%f.3f\n", jaro("MARTHA"@$_[0], @$_[1]) "MARHTA"));for
['MARTHA', 'MARHTA'], ['DIXON', 'DICKSONX'], ['JELLYFISH', 'SMELLYFISH'],
printf("%f\n", jaro("DIXON", "DICKSONX"));
['I repeat myself', 'I repeat myself'], ['', ''];</syntaxhighlight>
printf("%f\n", jaro("JELLYFISH", "SMELLYFISH"));</lang>
{{out}}
<pre>0.944
0.944444767
0.766667896
1.000
0.896296
1.000</pre>
 
=={{header|Perl 6}}==
{{trans|Perl}}
<lang perl6>sub jaro ($s, $t) {
 
return 1 if $s eq $t;
 
my $s_len = + my @s = $s.comb;
my $t_len = + my @t = $t.comb;
 
my $match_distance = ($s_len max $t_len) div 2 - 1;
 
my @s_matches;
my @t_matches;
my $matches = 0;
 
for ^@s -> $i {
 
my $start = 0 max $i - $match_distance;
my $end = $i + $match_distance min $t_len;
 
for $start .. $end -> $j {
@t_matches[$j] and next;
@s[$i] eq @t[$j] or next;
@s_matches[$i] = 1;
@t_matches[$j] = 1;
$matches++;
last;
}
}
 
return 0 if $matches == 0;
 
my $k = 0;
my $transpositions = 0;
 
for ^@s -> $i {
@s_matches[$i] or next;
until @t_matches[$k] { ++$k }
@s[$i] eq @t[$k] or ++$transpositions;
++$k;
}
 
($matches / $s_len + $matches / $t_len +
(($matches - $transpositions / 2) / $matches)) / 3;
}
 
printf("%f\n", jaro("MARTHA", "MARHTA"));
printf("%f\n", jaro("DIXON", "DICKSONX"));
printf("%f\n", jaro("JELLYFISH", "SMELLYFISH"));</lang>
{{out}}
<pre>
0.944444
0.766667
0.896296
</pre>
 
=={{header|Phix}}==
<!--<syntaxhighlight lang="phix">(phixonline)-->
<lang Phix>function jaro(string str1, str2)
<span style="color: #008080;">function</span> <span style="color: #000000;">jaro</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">str1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">str2</span><span style="color: #0000FF;">)</span>
str1 = trim(upper(str1))
<span style="color: #000000;">str1</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">trim</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">upper</span><span style="color: #0000FF;">(</span><span style="color: #000000;">str1</span><span style="color: #0000FF;">))</span>
str2 = trim(upper(str2))
<span style="color: #000000;">str2</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">trim</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">upper</span><span style="color: #0000FF;">(</span><span style="color: #000000;">str2</span><span style="color: #0000FF;">))</span>
integer len1 = length(str1),
<span style="color: #004080;">integer</span> <span style="color: #000000;">len1</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">str1</span><span style="color: #0000FF;">),</span>
len2 = length(str2),
<span style="color: #000000;">len2</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">str2</span><span style="color: #0000FF;">),</span>
match_distance = floor(max(len1,len2)/2)-1,
<span style="color: #000000;">match_distance</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">max</span><span style="color: #0000FF;">(</span><span style="color: #000000;">len1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">len2</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span>
match_count = 0,
<span style="color: #000000;">match_count</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span>
half_transposed = 0
<span style="color: #000000;">half_transposed</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
 
if len1==0 then return len2==0 end if
<span style="color: #008080;">if</span> <span style="color: #000000;">len1</span><span style="color: #0000FF;">==</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">len2</span><span style="color: #0000FF;">==</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
 
-- count the number of matches
<span style="color: #000080;font-style:italic;">-- count the number of matches</span>
sequence m1 = repeat(false,len1),
<span style="color: #004080;">sequence</span> <span style="color: #000000;">m1</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #004600;">false</span><span style="color: #0000FF;">,</span><span style="color: #000000;">len1</span><span style="color: #0000FF;">),</span>
m2 = repeat(false,len2)
<span style="color: #000000;">m2</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #004600;">false</span><span style="color: #0000FF;">,</span><span style="color: #000000;">len2</span><span style="color: #0000FF;">)</span>
for i=1 to len1 do
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">len1</span> <span style="color: #008080;">do</span>
for k=max(1,i-match_distance)
<span style="color: #008080;">for</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">=</span><span style="color: #7060A8;">max</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">i</span><span style="color: #0000FF;">-</span><span style="color: #000000;">match_distance</span><span style="color: #0000FF;">)</span>
to min(len2,i+match_distance) do
<span style="color: #008080;">to</span> <span style="color: #7060A8;">min</span><span style="color: #0000FF;">(</span><span style="color: #000000;">len2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">i</span><span style="color: #0000FF;">+</span><span style="color: #000000;">match_distance</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
if not m2[k] then
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #000000;">m2</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
if str1[i]=str2[k] then
<span style="color: #008080;">if</span> <span style="color: #000000;">str1</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">str2</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
m1[i] = true
<span style="color: #000000;">m1</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span>
m2[k] = true
<span style="color: #000000;">m2</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span>
match_count += 1
<span style="color: #000000;">match_count</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
exit
end if <span style="color: #008080;">exit</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
if match_count==0 then return 0 end if
<span style="color: #008080;">if</span> <span style="color: #000000;">match_count</span><span style="color: #0000FF;">==</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
-- count the number of half-transpositions
<span style="color: #000080;font-style:italic;">-- count the number of half-transpositions</span>
integer k = 1
<span style="color: #004080;">integer</span> <span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
for i=1 to len1 do
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">len1</span> <span style="color: #008080;">do</span>
if m1[i] then
<span style="color: #008080;">if</span> <span style="color: #000000;">m1</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
while not m2[k] do k += 1 end while
<span style="color: #008080;">while</span> <span style="color: #008080;">not</span> <span style="color: #000000;">m2</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">do</span> <span style="color: #000000;">k</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span> <span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
half_transposed += (str1[i]!=str2[k])
<span style="color: #000000;">half_transposed</span> <span style="color: #0000FF;">+=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">str1</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]!=</span><span style="color: #000000;">str2</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">])</span>
k += 1
<span style="color: #000000;">k</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
integer transpositions = floor(half_transposed/2),
<span style="color: #004080;">integer</span> <span style="color: #000000;">transpositions</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">half_transposed</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">),</span>
not_transposed = match_count - transpositions
<span style="color: #000000;">not_transposed</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">match_count</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">transpositions</span>
--
<span style="color: #000080;font-style:italic;">--
-- return the average of:
-- return the average of:
-- percentage/fraction of the first string matched,
-- percentage/fraction of the secondfirst string matched, and
-- percentage/fraction of matchesthe thatsecond werestring notmatched, transposed.and
-- percentage/fraction of matches that were not transposed.
--
--</span>
return (match_count/len1 +
<span style="color: #008080;">return</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">match_count</span><span style="color: #0000FF;">/</span><span style="color: #000000;">len1</span> <span style="color: #0000FF;">+</span>
match_count/len2 +
<span style="color: #000000;">match_count</span><span style="color: #0000FF;">/</span><span style="color: #000000;">len2</span> <span style="color: #0000FF;">+</span>
not_transposed/match_count)/3
<span style="color: #000000;">not_transposed</span><span style="color: #0000FF;">/</span><span style="color: #000000;">match_count</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">3</span>
end function
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
 
constant testcouples = {{"CRATE","TRACE"},
<span style="color: #008080;">constant</span> <span style="color: #000000;">testcouples</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #008000;">"CRATE"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"TRACE"</span><span style="color: #0000FF;">},</span>
{"JONES","JOHNSON"},
<span style="color: #0000FF;">{</span><span style="color: #008000;">"JONES"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"JOHNSON"</span><span style="color: #0000FF;">},</span>
{"ABCVWXYZ","CABVWXYZ"},
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ABCVWXYZ"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"CABVWXYZ"</span><span style="color: #0000FF;">},</span>
{"DWAYNE","DUANE"},
<span style="color: #0000FF;">{</span><span style="color: #008000;">"DWAYNE"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"DUANE"</span><span style="color: #0000FF;">},</span>
{"MARTHA", "MARHTA"},
<span style="color: #0000FF;">{</span><span style="color: #008000;">"MARTHA"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"MARHTA"</span><span style="color: #0000FF;">},</span>
{"DIXON", "DICKSONX"},
<span style="color: #0000FF;">{</span><span style="color: #008000;">"DIXON"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"DICKSONX"</span><span style="color: #0000FF;">},</span>
{"JELLYFISH", "SMELLYFISH"}}
<span style="color: #0000FF;">{</span><span style="color: #008000;">"JELLYFISH"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"SMELLYFISH"</span><span style="color: #0000FF;">}}</span>
 
for i=1 to length(testcouples) do
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">testcouples</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
string {s1, s2} = testcouples[i]
<span style="color: #004080;">string</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">s1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">s2</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">testcouples</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
printf(1,"%f <== jaro(\"%s\", \"%s\")\n",{jaro(s1,s2),s1,s2})
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%f &lt;== jaro(\"%s\", \"%s\")\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">jaro</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">s2</span><span style="color: #0000FF;">),</span><span style="color: #000000;">s1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">s2</span><span style="color: #0000FF;">})</span>
end for</lang>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Line 1,763 ⟶ 2,539:
 
{{Works with|Python|3}}
<langsyntaxhighlight lang="python">'''Jaro distance'''
 
from __future__ import division
Line 1,826 ⟶ 2,602:
 
if __name__ == '__main__':
main()</langsyntaxhighlight>
{{out}}
<pre>jaro('MARTHA', 'MARHTA') = 0.9444444444
Line 1,836 ⟶ 2,612:
{{Trans|Haskell}}
{{Works with|Python|3}}
<langsyntaxhighlight lang="python">'''Jaro distance between two strings'''
 
from functools import reduce
import itertools
 
 
# --------------------- JARO FUNCTION ----------------------
 
# jaro :: String -> String -> Float
Line 1,846 ⟶ 2,624:
'''The Jaro distance between two strings.'''
def go(s1, s2):
m, t = fanArrowap(compose(Tuple, len)(transpositionSum)(
matches(s1, s2)transpositionSum
)(matches(s1, s2))
return 0 if 0 == m else (
(1 / 3) * ((m / len(s1)) + (m / len(s2)) + ((m - t) / m))
m / len(s2)
) + ((m - t) / m))
)
return lambda y: go(x, y)
 
 
# -------------------------- TEST --------------------------
# main :: IO ()
def main():
'''TestsSample word pairs'''
 
print(
tabulatedfTable('Jaro distances:\n')(str)(showPrecision(3))(
showPrecision(3)
)(
uncurry(jaro)
)([
Line 1,871 ⟶ 2,654:
 
 
# JARO HELPER FUNCTIONS ----------------- JARO HELPER FUNCTIONS ------------------
 
 
# transpositionSum :: [(Int, Char)] -> Int
Line 1,889 ⟶ 2,671:
 
[(_, xs), (l2, ys)] = sorted(map(
fanArrowap(compose(Tuple, len))(list), [s1, s2]
))
r = l2 // 2 - 1
Line 1,909 ⟶ 2,691:
 
 
# GENERIC FUNCTIONS ------------------- GENERIC FUNCTIONS --------------------
 
# Just :: a -> Maybe a
def Just(x):
'''Constructor for an inhabited Maybe (option type) value.'''
Wrapper containing the result of a computation.
'''
return {'type': 'Maybe', 'Nothing': False, 'Just': x}
 
Line 1,919 ⟶ 2,703:
# Nothing :: Maybe a
def Nothing():
'''Constructor for an empty Maybe (option type) value.'''
Empty wrapper returned where a computation is not possible.
'''
return {'type': 'Maybe', 'Nothing': True}
 
 
# composeTuple (<<<,) :: (ba -> c)b -> (a ->, b) -> a -> c
def composeTuple(gx):
'''Constructor for a pair of values,
'''Function composition.'''
possibly of two different types.
return lambda f: lambda x: g(f(x))
'''
def go(y):
return (
x + (y,)
) if isinstance(x, tuple) else (x, y)
return go
 
 
# ap :: (a -> b -> c) -> (a -> b) -> a -> c
def ap(f):
'''Applicative instance for functions.
'''
def go(g):
def fxgx(x):
return f(x)(
g(x)
)
return fxgx
return go
 
 
# compose :: ((a -> a), ...) -> (a -> a)
def compose(*fs):
'''Composition, from right to left,
of a series of functions.
'''
def go(f, g):
def fg(x):
return f(g(x))
return fg
return reduce(go, fs, lambda x: x)
 
 
Line 1,932 ⟶ 2,749:
# drop :: Int -> String -> String
def drop(n):
'''The sublist of xs beginning at (zero-based) index n.'''
(zero-based) index n.
'''
def go(xs):
if isinstance(xs, (list, tuple, str)):
return xs[n:]
else:
take(n)(xs)
return xs
return lambda xs: go(xs)
 
 
Line 1,946 ⟶ 2,765:
'''Just the index of the first element in xs
which is equal to x,
or Nothing if there is no such element.'''
'''
def go(xs):
try:
Line 1,952 ⟶ 2,772:
except ValueError:
return Nothing()
return lambda xs: go(xs)
 
 
# fanArrow (&&&) :: (a -> b) -> (a -> c) -> (a -> (b, c))
def fanArrow(f):
'''A tuple of the outputs of two separate functions
applied to the same value.'''
return lambda g: lambda x: (f(x), g(x))
 
 
# fst :: (a, b) -> a
def fst(tpl):
'''First componentmember of a tuplepair.'''
return tpl[0]
 
Line 1,972 ⟶ 2,785:
'''Either the default value v, if m is Nothing,
or the application of f to x,
where the Maybe valuem is Just(x).'''
'''
return lambda f: lambda m: v if m.get('Nothing') else (
return lambda f: lambda f(m.get: v if ('Just'))
None is m or m.get('Nothing')
)
) else f(m.get('Just'))
 
 
Line 1,985 ⟶ 2,799:
 
 
# tabulatedfTable :: String -> (a -> String) ->
# (b -> String) -> (a -> (b) -> String)[a] -> String
def fTable(s):
# (a -> b) -> [a] -> String
def tabulated(s):
'''Heading -> x display function -> fx display function ->
f -> value listxs -> tabular string.'''
'''
def go(xShow, fxShow, f, xs):
def w = max(map(compose(len)gox(xShow), xs)):
returndef s + '\n' + '\n'.joingofx(fxShow):
xShow(x).rjust(w,def ' ') + ' -> ' + fxShowgof(f(x)) for x in xs:
def goxs(xs):
ys = [xShow(x) for x in xs]
return lambda xShow: lambda fxShow: lambda f: lambda xs: go(
xShow, fxShow, f w = max(map(len, xsys))
 
)
def arrowed(x, y):
return y.rjust(w, ' ') + (
' -> ' + fxShow(f(x))
)
return s + '\n' + '\n'.join(
map(arrowed, xs, ys)
)
return goxs
return gof
return gofx
return gox
 
 
Line 2,005 ⟶ 2,829:
def take(n):
'''The prefix of xs of length n,
or xs itself if n > length xs.'''
'''
islice = itertools.islice
 
return lambda xs: (
def go(xs[0):n]
ifreturn isinstance(xs, list)
else list(islice(xs, xs[0:n))]
if isinstance(xs, (list, tuple))
)
else list(islice(xs, n))
)
return go
 
 
Line 2,024 ⟶ 2,852:
# MAIN ---
if __name__ == '__main__':
main()</langsyntaxhighlight>
{{Out}}
<pre>Jaro distances:
Line 2,040 ⟶ 2,868:
Returns an exact value for the Jaro distance.
 
<langsyntaxhighlight lang="racket">#lang racket/base
;; {{trans|C}}
(require data/bit-vector)
Line 2,107 ⟶ 2,935:
(exact->inexact (jaro-distance "DIXON" "DICKSONX")); 0.766667
(jaro-distance "JELLYFISH" "SMELLYFISH"); 0.896296
(exact->inexact (jaro-distance "JELLYFISH" "SMELLYFISH"))); 0.896296</langsyntaxhighlight>
 
{{out}}
Line 2,117 ⟶ 2,945:
121/135
0.8962962962962963</pre>
 
=={{header|Raku}}==
(formerly Perl 6)
{{trans|Perl}}
<syntaxhighlight lang="raku" line>sub jaro ($s, $t) {
return 1 if $s eq $t;
 
my $s-len = + my @s = $s.comb;
my $t-len = + my @t = $t.comb;
my $match-distance = ($s-len max $t-len) div 2 - 1;
 
my ($matches, @s-matches, @t-matches);
for ^@s -> $i {
my $start = 0 max $i - $match-distance;
my $end = $i + $match-distance min ($t-len - 1);
 
for $start .. $end -> $j {
next if @t-matches[$j] or @s[$i] ne @t[$j];
(@s-matches[$i], @t-matches[$j]) = (1, 1);
$matches++ and last;
}
}
return 0 unless $matches;
 
my ($k, $transpositions) = (0, 0);
for ^@s -> $i {
next unless @s-matches[$i];
$k++ until @t-matches[$k];
$transpositions++ if @s[$i] ne @t[$k];
$k++;
}
 
( $matches/$s-len + $matches/$t-len + (($matches - $transpositions/2) / $matches) ) / 3
}
 
say jaro(.key, .value).fmt: '%.3f' for
'MARTHA' => 'MARHTA', 'DIXON' => 'DICKSONX', 'JELLYFISH' => 'SMELLYFISH',
'I repeat myself' => 'I repeat myself', '' => '';
</syntaxhighlight>
{{out}}
<pre>0.944
0.767
0.896
1.000
1.000</pre>
 
=={{header|REXX}}==
<langsyntaxhighlight lang="rexx">/*REXX program computes the Jaro distance between two strings (or a list of strings).*/
@.= /*define a default for the @. array. */
parse arg @.1 /*obtain an optional character string. */
if @.1='' then do; @.1= 'MARTHA MARHTA' /*nothingNothing specified? Use the defaults.*/
@.12= 'MARTHADIXON MARHTADICKSONX'
@.23= 'DIXON JELLYFISH DICKSONXSMELLYFISH'
@.34= 'JELLYFISHDWAYNE SMELLYFISHDUANE'
@.4=end 'DWAYNE DUANE' /* [↑] embedded blanks are shown as is.*/
end
 
do j=1 while @.j\=='' /*process all the strings in the list. */
d=jaroDist jaroD(@.j)
say 'Jaro distance is ' format(d, , 58) " for strings: " @.j
end /*j*/ /* └──── digits past the decimal point.*/
exit 0 /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
jaroDistjaroD: procedure; arg s.1 s.2 .; L1= length(s.1); L2= length(s.2); m= 0
if L1==0 | L2==0 then return 0 /*check if any string is a null string.*/
f= max(L1, L2) % 2 - 1 - 1 /*calculate furthest distanced allowed.*/
r.= 0 /* [↓] see if the char is near enough.*/
do k=1 for L1; p= pos( substr(s.1, k, 1), s.2, max(1, k-f) ); r.k=p
r.k= p
if p\==0 & abs(p-k)<=f then m=m+1 /*if near enough, count it as a match. */
if p\==0 & abs(p-k)<=f then m= m+1 else r.k=0 /*if near enough, count it as a ···match. otherwise, don't count it.*/
end else r.k= 0 /*k ··· otherwise, don't count it.*/
t=0 end /*k*/
do ot=1 for L1; om=o-10
do o=1 iffor pos(L1; substr(s.1, om= o, - 1),; s.2)==0 | if r.o==0 | r.om==0 then iterate
if pos( substr(s.1, ifo, 1), rs.o<r.om2)==0 then t=t+1iterate
if r.o<r.om then t= t + 1
end /*o*/ /* [↑] count number of transpositions.*/
end /*o*/ /* [↑] count number of transpositions.*/
 
if m==0 then return 0
return (m/L1 + m/L2 + (m-t)/m) / 3</langsyntaxhighlight>
'''{{out|output''' |text=&nbsp; when using the default inputs:}}
<pre>
Jaro distance is 0.9444494444444 for strings: MARTHA MARHTA
Jaro distance is 0.7666776666667 for strings: DIXON DICKSONX
Jaro distance is 0.8963089629630 for strings: JELLYFISH SMELLYFISH
Jaro distance is 0.8222282222222 for strings: DWAYNE DUANE
</pre>
 
=={{header|Ring}}==
<langsyntaxhighlight lang="ring">
# Project : Jaro distance
 
Line 2,210 ⟶ 3,083:
b = temp
return [a, b]
</syntaxhighlight>
</lang>
Output:
<pre>
Line 2,219 ⟶ 3,092:
 
=={{header|Ruby}}==
<langsyntaxhighlight lang="ruby">def jaro(s, t)
return 1.0 if s == t
Line 2,266 ⟶ 3,139:
).each_slice(2) do |s,t|
puts "jaro(#{s.inspect}, #{t.inspect}) = #{'%.10f' % jaro(s, t)}"
end</langsyntaxhighlight>
{{out}}
<pre>
Line 2,276 ⟶ 3,149:
=={{header|Rust}}==
{{trans|C++}}
<langsyntaxhighlight lang="rust">use std::cmp;
 
pub fn jaro(s1: &str, s2: &str) -> f64 {
Line 2,316 ⟶ 3,189:
let pairs = [("MARTHA", "MARHTA"), ("DIXON", "DICKSONX"), ("JELLYFISH", "SMELLYFISH")];
for p in pairs.iter() { println!("{}/{} = {}", p.0, p.1, jaro(p.0, p.1)); }
}</langsyntaxhighlight>
{{Out}}
<pre>MARTHA/MARHTA = 0.9444444444444445
Line 2,324 ⟶ 3,197:
=={{header|Scala}}==
{{trans|Java}}
<langsyntaxhighlight lang="scala">object Jaro extends App {
 
def distance(s1: String, s2: String): Double = {
Line 2,360 ⟶ 3,233:
val strings = List(("MARTHA", "MARHTA"), ("DIXON", "DICKSONX"), ("JELLYFISH", "SMELLYFISH"))
strings.foreach { s => println(distance(s._1, s._2)) }
}</langsyntaxhighlight>
 
=={{header|Sidef}}==
<langsyntaxhighlight lang="ruby">func jaro(s, t) {
 
return 1 if (s == t)
Line 2,413 ⟶ 3,286:
] {
say "jaro(#{pair.map{.join.dump}.join(', ')}) = #{'%.10f' % jaro(pair...)}"
}</langsyntaxhighlight>
{{out}}
<pre>
Line 2,424 ⟶ 3,297:
Here we use the [https://ideas.repec.org/c/boc/bocode/s457850a.html jarowinkler] package from SSC. To install the package, type
 
<syntaxhighlight lang ="stata">ssc install jarowinkler</langsyntaxhighlight>
 
Now the program for the task:
 
<langsyntaxhighlight lang="stata">clear
input str20 a str20 b
DWAYNE DUANE
Line 2,439 ⟶ 3,312:
format %8.3f jaro
format %-20s a b
list a b jaro</langsyntaxhighlight>
 
'''Output'''
Line 2,451 ⟶ 3,324:
4. | JELLYFISH SMELLYFISH 0.896 |
+--------------------------------+</pre>
 
=={{header|Swift}}==
<langsyntaxhighlight Swiftlang="swift"> func jaroWinklerMatch(_ s: String, _ t: String) -> Double {
let s_len: Int = s.count
let t_len: Int = t.count
Line 2,541 ⟶ 3,415:
print("DIXON/DICKSONX:", jaroWinklerMatch("DIXON", "DICKSONX"))
print("JELLYFISH/SMELLYFISH:", jaroWinklerMatch("JELLYFISH", "SMELLYFISH"))
</syntaxhighlight>
</lang>
 
{{out}}
Line 2,552 ⟶ 3,426:
 
=={{header|Tcl}}==
<langsyntaxhighlight Tcllang="tcl">proc jaro {s1 s2} {
set l1 [string length $s1]
set l2 [string length $s2]
Line 2,589 ⟶ 3,463:
} {
puts "[jaro $s $t]:\t$s / $t"
}</langsyntaxhighlight>
 
{{out}}
Line 2,597 ⟶ 3,471:
0.8962962962962964: JELLYFISH / SMELLYFISH</pre>
 
=={{header|Turbo-Basic XL}}==
<syntaxhighlight lang="turbobasic">
10 DIM Word_1$(20), Word_2$(20), Z$(20)
11 CLS
20 Word_1$="MARTHA" : Word_2$="MARHTA" : ? Word_1$;" - ";Word_2$ : EXEC _JWD_ : ?
30 Word_1$="DIXON" : Word_2$="DICKSONX" : ? Word_1$;" - ";Word_2$ : EXEC _JWD_ : ?
40 Word_1$="JELLYFISH" : Word_2$="SMELLYFISH" : ? Word_1$;" - ";Word_2$ : EXEC _JWD_ : ?
 
11000 END
12000 REM JaroWinklerDistance INPUT(Word_1$, Word_2$) USE(Z$, I, J, K, L, M, N, S1, S2, Min, Max) RETURN(FLOAT Result)
12000 PROC _JWD_
12010 Result=0 : S1=LEN(Word_1$) : S2=LEN(Word_2$)
12020 IF S1>S2 THEN Z$=Word_1$ : Word_1$=Word_2$ : Word_2$=Z$ : M=S1 : S1=S2 : S2=M
12030 J=1: M=0 : N=0 : L=INT(S2/2) : Z$=Word_2$
12040 FOR I=1 TO S1
12050 IF Word_1$(I,I)=Word_2$(J,J) THEN M=M+1: Word_2$(J,J)=" ": GO# JMP_JWD
12060 Max=1 : IF Max<(I-L) THEN Max=I-L
12070 Min=S2 : IF Min>(I+L-1) THEN Min=I+L-1
12080 FOR K=Max TO Min
12090 IF Word_1$(I,I)=Word_2$(K,K) THEN N=N+1: M=M+1: Word_2$(K,K)=" ": IF K>J THEN J=K
12100 NEXT K
12110 #JMP_JWD : IF J<S2 THEN J=J+1
12120 NEXT I
12130 IF M=0
12140 Result=0 : REM jaro distance
12150 ELSE
12160 N=INT(N/2)
12170 Result=(M/S1+M/S2+((M-N)/M))/3. : REM jaro distance
12180 ENDIF
12190 ? "Jaro Distance=";Result
12200 Min=S1 : IF Min>S2 THEN Min=S2
12210 M=Min : IF M>3 THEN M=3
12220 M=M+1 : L=0 : Word_2$=Z$ : IF M>Min THEN M=Min
12230 FOR I=1 TO M
12240 IF Word_1$(I,I)=Word_2$(I,I)
12250 L=L+1
12260 ELSE
12270 EXIT
12280 ENDIF
12290 NEXT I
12300 Result=Result + (L*0.1*(1.0 - Result)) : REM Winkler
12310 ? "Jaro Winkler Distance=";Result
12320 ENDPROC
</syntaxhighlight>
{{out}}
<pre>MARTHA, MARHTA: 0.9444444433
DIXON, DICKSONX: 0.7666666666
JELLYFISH, SMELLYFISH: 0.8962962933</pre>
 
=={{header|VBA}}==
<syntaxhighlight lang="vb">
<lang vb>
Option Explicit
 
Line 2,644 ⟶ 3,566:
JaroWinkler = JaroWinkler + (1 - JaroWinkler) * l * WorksheetFunction.Min(0.25, p)
End Function
</syntaxhighlight>
</lang>
 
=={{header|V (Vlang)}}==
 
{{trans|Python}}
<syntaxhighlight lang="v (vlang)">import math
 
fn jaro(str1 string, str2 string) f64 {
s1_len := str1.len
s2_len := str2.len
if s1_len == 0 && s2_len == 0 {
return 1
}
if s1_len == 0 || s2_len == 0 {
return 0
}
match_distance := math.max<int>(s1_len,s2_len)/2 - 1
mut str1_matches := []bool{len: s1_len}
mut str2_matches := []bool{len: s2_len}
mut matches := 0
mut transpositions := 0.0
for i in 0..s1_len {
start := math.max<int>(0,i - match_distance)
end := math.min<int>(i + match_distance, s2_len)
for k in start..end {
if str2_matches[k] {
continue
}
if str1[i] != str2[k] {
continue
}
str1_matches[i] = true
str2_matches[k] = true
matches++
break
}
}
if matches == 0 {
return 0
}
mut k := 0
for i in 0..s1_len {
if !str1_matches[i] {
continue
}
for !str2_matches[k] {
k++
}
if str1[i] != str2[k] {
transpositions++
}
k++
}
transpositions /= 2
return (matches/f64(s1_len) +
matches/f64(s2_len) +
(matches-transpositions)/matches) / 3
}
fn main() {
println(jaro("MARTHA", "MARHTA"))
println(jaro("DIXON", "DICKSONX"))
println(jaro("JELLYFISH", "SMELLYFISH"))
}</syntaxhighlight>
{{out}}
<pre>0.9444444444444445
0.7666666666666666
0.8962962962962964
</pre>
 
=={{header|Wren}}==
{{trans|Go}}
{{libheader|Wren-fmt}}
<syntaxhighlight lang="wren">import "./fmt" for Fmt
 
var jaro = Fn.new { |s1, s2|
var le1 = s1.count
var le2 = s2.count
if (le1 == 0 && le2 == 0) return 1
if (le1 == 0 || le2 == 0) return 0
var dist = (le2 > le1) ? le2 : le1
dist = (dist/2).floor - 1
var matches1 = List.filled(le1, false)
var matches2 = List.filled(le2, false)
var matches = 0
var transpos = 0
for (i in 0...s1.count) {
var start = i - dist
if (start < 0) start = 0
var end = i + dist + 1
if (end > le2) end = le2
var k = start
while (k < end) {
if (!(matches2[k] || s1[i] != s2[k])) {
matches1[i] = true
matches2[k] = true
matches = matches + 1
break
}
k = k + 1
}
}
if (matches == 0) return 0
var k = 0
for (i in 0...s1.count) {
if (matches1[i]) {
while(!matches2[k]) k = k + 1
if (s1[i] != s2[k]) transpos = transpos + 1
k = k + 1
}
}
transpos = transpos / 2
return (matches/le1 + matches/le2 + (matches - transpos)/matches) / 3
}
 
System.print(Fmt.f(0, jaro.call("MARTHA", "MARHTA")))
System.print(Fmt.f(0, jaro.call("DIXON", "DICKSONX")))
System.print(Fmt.f(0, jaro.call("JELLYFISH", "SMELLYFISH")))</syntaxhighlight>
 
{{out}}
<pre>
0.944444
0.766667
0.896296
</pre>
 
=={{header|zkl}}==
<langsyntaxhighlight lang="zkl"> //-->String of matched characters, ordered
fcn _jaro(str1,str2, matchDistance){
cs:=Sink(String);
Line 2,667 ⟶ 3,715:
( matches/s1Len + matches/s2Len +
((matches - transpositions)/matches) ) / 3.0
}</langsyntaxhighlight>
<langsyntaxhighlight lang="zkl">foreach s,t in (T(
T("MARTHA","MARHTA"), T("DIXON","DICKSONX"), T("JELLYFISH","SMELLYFISH"))){
println(0'|jaro("%s","%s") = %.10f|.fmt(s,t,jaro(s,t)));
}</langsyntaxhighlight>
{{out}}
<pre>
Line 2,681 ⟶ 3,729:
=={{header|ZX Spectrum Basic}}==
{{trans|FreeBASIC}}
<langsyntaxhighlight lang="zxbasic">10 LET a$="MARTHA": LET b$="MARHTA": PRINT a$;", ";b$;": ";: GO SUB 1000: PRINT jaro
20 LET a$="DIXON": LET b$="DICKSONX": PRINT a$;", ";b$;": ";: GO SUB 1000: PRINT jaro
30 LET a$="JELLYFISH": LET b$="SMELLYFISH": PRINT a$;", ";b$;": ";: GO SUB 1000: PRINT jaro
Line 2,702 ⟶ 3,750:
5000 REM Functions
5010 DEF FN x(a,b)=(a AND a>b)+(b AND a<b)+(a AND a=b): REM max function
5020 DEF FN n(a,b)=(a AND a<b)+(b AND a>b)+(a AND a=b): REM min function</langsyntaxhighlight>
{{out}}
<pre>MARTHA, MARHTA: 0.94444444
338

edits