Jaro similarity: Difference between revisions

Add C# implementation
No edit summary
(Add C# implementation)
 
(45 intermediate revisions by 23 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}}==
<langsyntaxhighlight Adalang="ada">with Ada.Text_IO;
 
procedure Jaro_Distances is
Line 152 ⟶ 296:
Show_Jaro ("JELLYFISH", "SMELLYFISH");
Show_Jaro (S1 (3 .. 8), S1 (13 .. 18));
end Jaro_Distances;</langsyntaxhighlight>
 
{{out}}
Line 162 ⟶ 306:
=={{header|ARM Assembly}}==
{{works with|as|Raspberry Pi}}
<syntaxhighlight lang="arm assembly">
<lang ARM Assembly>
 
/* ARM assembly Raspberry PI */
Line 516 ⟶ 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 572 ⟶ 731:
function max(x,y) { return((x > y) ? x : y) }
function min(x,y) { return((x < y) ? x : y) }
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 580 ⟶ 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 671 ⟶ 886:
printf("%f\n", jaro("DIXON", "DICKSONX"));
printf("%f\n", jaro("JELLYFISH", "SMELLYFISH"));
}</langsyntaxhighlight>
{{out}}
<pre>
Line 677 ⟶ 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 729 ⟶ 1,008:
cout << jaro("JELLYFISH", "SMELLYFISH") << endl;
return 0;
}</langsyntaxhighlight>
 
=={{header|Clojure}}==
<langsyntaxhighlight lang="clojure">
(ns test-project-intellij.core
(:gen-class))
Line 814 ⟶ 1,093:
(println (jaro "DIXON" "DICKSONX"))
(println (jaro "JELLYFISH" "SMELLYFISH"))
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 821 ⟶ 1,100:
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}}
<langsyntaxhighlight lang="cobol">
identification division.
program-id. JaroDistance.
Line 923 ⟶ 1,270:
((matches - transpositions / 2) / matches)) / 3
.
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 933 ⟶ 1,280:
=={{header|CoffeeScript}}==
{{trans|C++}}
<langsyntaxhighlight lang="coffeescript">jaro = (s1, s2) ->
l1 = s1.length
l2 = s2.length
Line 962 ⟶ 1,309:
console.log jaro "MARTHA", "MARHTA"
console.log jaro "DIXON", "DICKSONX"
console.log jaro "JELLYFISH", "SMELLYFISH"</langsyntaxhighlight>
{{Out}}
<pre>0.9444444444444445
Line 970 ⟶ 1,317:
=={{header|Crystal}}==
{{trans|Ruby}}
<langsyntaxhighlight lang="ruby">def jaro(s, t)
return 1.0 if s == t
Line 1,014 ⟶ 1,361:
JELLYFISH SMELLYFISH
).each_slice(2) { |(s ,t)| puts "jaro(#{s}, #{t}) = #{"%.10f" % jaro(s, t)}" }
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 1,024 ⟶ 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 1,063 ⟶ 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 1,128 ⟶ 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 1,139 ⟶ 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 1,174 ⟶ 1,613:
] 2 4 mnapply ;
 
MAIN: jaro-demo</langsyntaxhighlight>
{{out}}
<pre>
Line 1,184 ⟶ 1,623:
 
=={{header|FreeBASIC}}==
<langsyntaxhighlight lang="freebasic">' version 09-10-2016
' compile with: fbc -s console
 
Line 1,240 ⟶ 1,679:
Print : Print "hit any key to end program"
Sleep
End</langsyntaxhighlight>
{{out}}
<pre> jaro (MARTHA, MARHTA) = 0.9444444444444444
Line 1,247 ⟶ 1,686:
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package main
 
import "fmt"
Line 1,315 ⟶ 1,754:
fmt.Printf("%f\n", jaro("DIXON", "DICKSONX"))
fmt.Printf("%f\n", jaro("JELLYFISH", "SMELLYFISH"))
}</langsyntaxhighlight>
{{out}}
<pre>
Line 1,324 ⟶ 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,378 ⟶ 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,416 ⟶ 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,426 ⟶ 1,920:
Implementation:
 
<langsyntaxhighlight Jlang="j">jaro=: dyad define
d=. ((x >.&# y)%2)-1
e=. (x =/y) * d >: |x -/&(i.@#) y
Line 1,436 ⟶ 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,497 ⟶ 1,991:
System.out.println(jaro("JELLYFISH", "SMELLYFISH"));
}
}</langsyntaxhighlight>
{{out}}
<pre>
Line 1,506 ⟶ 2,000:
 
=={{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,607 ⟶ 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,660 ⟶ 2,278:
((matches->As(Float) - transpositions/2.0) / matches)) / 3.0;
}
}</langsyntaxhighlight>
 
{{output}}
Line 1,674 ⟶ 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,710 ⟶ 2,328:
jaroDist("DWAYNE","DUANE");
}
</langsyntaxhighlight>
 
{{Output}}
Line 1,722 ⟶ 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,778 ⟶ 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 my($s_len, @s) == 0 and(length $t_lens, ==split //, 0$s);
my($t_len, @t) = (length $t, split //, $t);
 
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 $matches = 0;
foreach my $i (0 .. $#s) {
 
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|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,919 ⟶ 2,539:
 
{{Works with|Python|3}}
<langsyntaxhighlight lang="python">'''Jaro distance'''
 
from __future__ import division
Line 1,982 ⟶ 2,602:
 
if __name__ == '__main__':
main()</langsyntaxhighlight>
{{out}}
<pre>jaro('MARTHA', 'MARHTA') = 0.9444444444
Line 1,992 ⟶ 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 2,002 ⟶ 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 2,027 ⟶ 2,654:
 
 
# JARO HELPER FUNCTIONS ----------------- JARO HELPER FUNCTIONS ------------------
 
 
# transpositionSum :: [(Int, Char)] -> Int
Line 2,045 ⟶ 2,671:
 
[(_, xs), (l2, ys)] = sorted(map(
fanArrowap(compose(Tuple, len))(list), [s1, s2]
))
r = l2 // 2 - 1
Line 2,065 ⟶ 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 2,075 ⟶ 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 2,088 ⟶ 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 2,102 ⟶ 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 2,108 ⟶ 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 2,128 ⟶ 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 2,141 ⟶ 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,161 ⟶ 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,180 ⟶ 2,852:
# MAIN ---
if __name__ == '__main__':
main()</langsyntaxhighlight>
{{Out}}
<pre>Jaro distances:
Line 2,196 ⟶ 2,868:
Returns an exact value for the Jaro distance.
 
<langsyntaxhighlight lang="racket">#lang racket/base
;; {{trans|C}}
(require data/bit-vector)
Line 2,263 ⟶ 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,277 ⟶ 2,949:
(formerly Perl 6)
{{trans|Perl}}
<syntaxhighlight lang="raku" perl6line>sub jaro ($s, $t) {
 
return 1 if $s eq $t;
 
my $s_lens-len = + my @s = $s.comb;
my $t_lent-len = + my @t = $t.comb;
my $match-distance = ($s-len max $t-len) div 2 - 1;
 
my $match_distance = ($s_len max $t_len) div 2 - 1;
 
my @s_matches;
my @t_matches;
my $matches = 0;
 
my ($matches, @s-matches, @t-matches);
for ^@s -> $i {
my $start = 0 max $i - $match-distance;
 
my $startend = 0 max= $i + $match-distance min ($match_distancet-len - 1);
my $end = $i + $match_distance min $t_len;
 
for $start .. $end -> $j {
next if @t_matchest-matches[$j] andor next@s[$i] ne @t[$j];
(@s-matches[$i] eq, @t-matches[$j]) = or(1, next1);
@s_matches[$i]matches++ =and 1last;
@t_matches[$j] = 1;
$matches++;
last;
}
}
return 0 unless $matches;
 
returnmy 0 if($k, $matchestranspositions) == (0, 0);
 
my $k = 0;
my $transpositions = 0;
 
for ^@s -> $i {
next unless @s_matchess-matches[$i] or next;
$k++ until @t_matchest-matches[$k] { ++$k };
$transpositions++ if @s[$i] eqne @t[$k] or ++$transpositions;
++$k++;
}
 
( $matches /$s-len + $matches/$s_lent-len + (($matches - $transpositions/2) / $t_lenmatches) +) / 3
(($matches - $transpositions / 2) / $matches)) / 3;
}
 
say jaro(.key, .value).fmt: '%.3f' for
printf("%f\n", jaro("MARTHA", "MARHTA"));
'MARTHA' => 'MARHTA', 'DIXON' => 'DICKSONX', 'JELLYFISH' => 'SMELLYFISH',
printf("%f\n", jaro("DIXON", "DICKSONX"));
'I repeat myself' => 'I repeat myself', '' => '';
printf("%f\n", jaro("JELLYFISH", "SMELLYFISH"));</lang>
</syntaxhighlight>
{{out}}
<pre>0.944
0.944444767
0.766667896
1.000
0.896296
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.*/
@.2= 'DIXON DICKSONX'
@.3= 'JELLYFISH SMELLYFISH'
@.4= 'DWAYNE DUANE'
end /* [↑] embedded blanks are listshown as is.*/
 
do j=1 while @.j\=='' /*process all the strings in the list. */
do j=1 while @.j\=='' /*process all the strings in the list. */
d= jaroDist(@.j)
d= jaroD(@.j)
say 'Jaro distance is ' format(d, , 5) " for strings: " @.j
end say 'Jaro /*j*/distance is ' format(d, , 8) " for strings: " /* └──── digits past the decimal point@.*/j
exit end /*j*/ /*stick a└──── forkdigits inpast it,the decimal we're all donepoint. */
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 /*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*/
t= 0
do o=1 for L1; om= o - 1
do o=1 if pos(for substr(s.1,L1; om= o, - 1),; s.2)==0 | if r.o==0 | r.om==0 then iterate
if rpos( substr(s.1, o<r.om, 1), then ts.2)==0 t +then 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,421 ⟶ 3,083:
b = temp
return [a, b]
</syntaxhighlight>
</lang>
Output:
<pre>
Line 2,430 ⟶ 3,092:
 
=={{header|Ruby}}==
<langsyntaxhighlight lang="ruby">def jaro(s, t)
return 1.0 if s == t
Line 2,477 ⟶ 3,139:
).each_slice(2) do |s,t|
puts "jaro(#{s.inspect}, #{t.inspect}) = #{'%.10f' % jaro(s, t)}"
end</langsyntaxhighlight>
{{out}}
<pre>
Line 2,487 ⟶ 3,149:
=={{header|Rust}}==
{{trans|C++}}
<langsyntaxhighlight lang="rust">use std::cmp;
 
pub fn jaro(s1: &str, s2: &str) -> f64 {
Line 2,527 ⟶ 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,535 ⟶ 3,197:
=={{header|Scala}}==
{{trans|Java}}
<langsyntaxhighlight lang="scala">object Jaro extends App {
 
def distance(s1: String, s2: String): Double = {
Line 2,571 ⟶ 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,624 ⟶ 3,286:
] {
say "jaro(#{pair.map{.join.dump}.join(', ')}) = #{'%.10f' % jaro(pair...)}"
}</langsyntaxhighlight>
{{out}}
<pre>
Line 2,635 ⟶ 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,650 ⟶ 3,312:
format %8.3f jaro
format %-20s a b
list a b jaro</langsyntaxhighlight>
 
'''Output'''
Line 2,664 ⟶ 3,326:
 
=={{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,753 ⟶ 3,415:
print("DIXON/DICKSONX:", jaroWinklerMatch("DIXON", "DICKSONX"))
print("JELLYFISH/SMELLYFISH:", jaroWinklerMatch("JELLYFISH", "SMELLYFISH"))
</syntaxhighlight>
</lang>
 
{{out}}
Line 2,764 ⟶ 3,426:
 
=={{header|Tcl}}==
<langsyntaxhighlight Tcllang="tcl">proc jaro {s1 s2} {
set l1 [string length $s1]
set l2 [string length $s2]
Line 2,801 ⟶ 3,463:
} {
puts "[jaro $s $t]:\t$s / $t"
}</langsyntaxhighlight>
 
{{out}}
Line 2,808 ⟶ 3,470:
0.7666666666666666: DIXON / DICKSONX
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,855 ⟶ 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,878 ⟶ 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,892 ⟶ 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,913 ⟶ 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
DIXON, DICKSONX: 0.76666667
JELLYFISH, SMELLYFISH: 0.8962963</pre>
 
=={{header|ATARI TURBO-BASIC XL}}==
<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) THEN Min=I+L
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
</lang>
{{out}}
<pre>MARTHA, MARHTA: 0.9444444433
DIXON, DICKSONX: 0.7666666666
JELLYFISH, SMELLYFISH: 0.8962962933</pre>
 
 
=={{header|ATARI ACTION!}}==
<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) THEN Min=I+L 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,"MARTHA") SCopy(Word_2,"MARHTA")
PrintF("%S - %S%E",Word_1,Word_2)
result=JaroDistance(Word_1,Word_2)
PrintF("Jaro Distance=%U%E%E",result)
 
SCopy(Word_1,"DIXON") SCopy(Word_2,"DICKSONX")
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
</lang>
{{out}}
<pre>MARTHA, MARHTA: 94
DIXON, DICKSONX: 76
JELLYFISH, SMELLYFISH: 89
</pre>
338

edits