Data commit

This commit is contained in:
Ingy döt Net 2023-07-01 11:58:00 -04:00
parent 7387c8f97b
commit cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions

View file

@ -0,0 +1,2 @@
---
from: http://rosettacode.org/wiki/Levenshtein_distance

View file

@ -0,0 +1,27 @@
<br>
In information theory and computer science, the '''Levenshtein distance''' is a [[wp:string metric|metric]] for measuring the amount of difference between two sequences (i.e. an [[wp:edit distance|edit distance]]). The Levenshtein distance between two strings is defined as the minimum number of edits needed to transform one string into the other, with the allowable edit operations being insertion, deletion, or substitution of a single character.
;Example:
The Levenshtein distance between "'''kitten'''" and "'''sitting'''" is 3, since the following three edits change one into the other, and there isn't a way to do it with fewer than three edits:
::# &nbsp; '''k'''itten &nbsp; '''s'''itten &nbsp; (substitution of 'k' with 's')
::# &nbsp; sitt'''e'''n &nbsp; sitt'''i'''n &nbsp; (substitution of 'e' with 'i')
::# &nbsp; sittin &nbsp; sittin'''g''' &nbsp; (insert 'g' at the end).
<br>
''The Levenshtein distance between &nbsp; "'''rosettacode'''", &nbsp; "'''raisethysword'''" &nbsp; is &nbsp; '''8'''.
''The distance between two strings is same as that when both strings are reversed.''
;Task:
Implements a Levenshtein distance function, or uses a library function, to show the Levenshtein distance between &nbsp; "kitten" &nbsp; and &nbsp; "sitting".
;Related task:
* &nbsp; [[Longest common subsequence]]
{{Template:Strings}}
<br><br>

View file

@ -0,0 +1,18 @@
F minimumEditDistance(=s1, =s2)
I s1.len > s2.len
(s1, s2) = (s2, s1)
V distances = Array(0 .. s1.len)
L(char2) s2
V newDistances = [L.index + 1]
L(char1) s1
I char1 == char2
newDistances.append(distances[L.index])
E
newDistances.append(1 + min((distances[L.index], distances[L.index + 1], newDistances.last)))
distances = newDistances
R distances.last
print(minimumEditDistance(kitten, sitting))
print(minimumEditDistance(rosettacode, raisethysword))

View file

@ -0,0 +1,173 @@
* Levenshtein distance - 22/04/2020
LEVENS CSECT
USING LEVENS,R13 base register
B 72(R15) skip savearea
DC 17F'0' savearea
SAVE (14,12) save previous context
ST R13,4(R15) link backward
ST R15,8(R13) link forward
LR R13,R15 set addressability
LA R8,1 ii=1
DO WHILE=(C,R8,LE,NN) do ii=1 to nn
LR R1,R8 ii
SLA R1,5 *32
LA R4,SS-32(R1) @ss(ii,1)
MVC S1,0(R4) s1=ss(ii,1)
LR R1,R8 ii
SLA R1,1 *2
LA R1,1(R1) +1
SLA R1,4 *16
LA R4,SS-32(R1) @ss(ii,2)
MVC S2,0(R4) s2=ss(ii,2)
LA R1,S1 @s1
BAL R14,LENGTHST call length
AH R0,=H'1' +1
ST R0,N1 n1=length(s1)+1
LA R1,S2 @s2
BAL R14,LENGTHST call length
AH R0,=H'1' +1
ST R0,N2 n2=length(s2)+1
L R4,N1 n1
IF C,R4,EQ,=F'1' THEN if n1=1 then
L R3,N2 n2
BCTR R3,0 lev=n2-1
B RET goto ret
ENDIF , endif
L R4,N2 n2
IF C,R4,EQ,=F'1' THEN if n2=1 then
L R3,N1 n1
BCTR R3,0 lev=n1-1
B RET goto ret
ENDIF , endif
LA R6,1 i=1
DO WHILE=(C,R6,LE,N1) do i=1 to n1
LR R2,R6 i
BCTR R2,0 -1
LR R1,R6 i
SLA R1,6 *64
ST R2,D-64(R1) d(i,1)=i-1
LA R6,1(R6) i++
ENDDO , enddo i
LA R7,1 j=1
DO WHILE=(C,R7,LE,N2) do j=1 to n2
LR R2,R7 j
BCTR R2,0 j-1
LR R1,R7 j
SLA R1,2 *4
ST R2,D-4(R1) d(1,j)=j-1
LA R7,1(R7) j++
ENDDO , enddo j
LA R6,2 i=2
DO WHILE=(C,R6,LE,N1) do i=2 to n1
LA R4,S1-2 @s1-2
AR R4,R6 +i
MVC C1(1),0(R4) c1=substr(s1,i-1,1)
LA R7,2 j=2
DO WHILE=(C,R7,LE,N2) do j=2 to n2
LA R4,S2-2 @s2-2
AR R4,R7 +j
MVC C2(1),0(R4) c2=substr(s2,j-1,1)
LR R1,R6 i
SH R1,=H'2' -2
SLA R1,4 *16
AR R1,R7 +j
SLA R1,2 *4
L R2,D-4(R1) d(i-1,j)
LA R2,1(R2) +1
ST R2,D1 d1=d(i-1,j)+1
LR R2,R7 j
BCTR R2,0 -1
LR R1,R6 i
BCTR R1,0 -1
SLA R1,4 *16
AR R1,R2 +(j-1)
SLA R1,2 *4
L R2,D-4(R1) d(i,j-1)
LA R2,1(R2) +1
ST R2,D2 d2=d(i,j-1)+1
IF CLC,C1,NE,C2 THEN if c1<>c2 then
LA R9,1 x=1
ELSE , else
SR R9,R9 x=0
ENDIF , endif
LR R1,R6 i
SH R1,=H'2' i-2
LR R2,R7 j
BCTR R2,0 j-1
SLA R1,4 *16
AR R1,R2 +(j-1)
SLA R1,2 *4
L R2,D-4(R1) d(i-1,j-1)
AR R2,R9 +x
ST R2,D3 d3=d(i-1,j-1)+x
L R4,D1 d1
IF C,R4,LT,D2 THEN if d1<d2 then
IF C,R4,LT,D3 THEN if d1<d3 then
L R10,D1 dd=d1
ELSE , else
L R10,D3 dd=d3
ENDIF , endif
ELSE , else
L R4,D2 d2
IF C,R4,LT,D3 THEN if d2<d3 then
L R10,D2 dd=d2
ELSE , else
L R10,D3 dd=d3
ENDIF , endif
ENDIF , endif
LR R1,R6 i
BCTR R1,0 i-1
SLA R1,4 *16
AR R1,R7 +j
SLA R1,2 *4
ST R10,D-4(R1) d(i,j)=dd
LA R7,1(R7) j++
ENDDO , enddo j
LA R6,1(R6) i++
ENDDO , enddo i
L R1,N1 n1
BCTR R1,0 -1
SLA R1,4 *16
A R1,N2 +n2
SLA R1,2 *4
L R3,D-4(R1) lev=d(n1,n2)
RET MVC PG,=CL80' ' clear buffer
MVC PG(16),S1 output s1
MVC PG+17(16),S2 output s2
XDECO R3,XDEC edit lev
MVC PG+34(5),XDEC+7 output lev
XPRNT PG,L'PG print bufffer
LA R8,1(R8) ii++
ENDDO , enddo ii
L R13,4(0,R13) restore previous savearea pointer
RETURN (14,12),RC=0 restore registers from calling save
LENGTHST CNOP 0,4 function lengthst(c)
LA R0,16 i=16
LA R1,15(R1) @ci
LENGTHS1 LTR R0,R0 while i>0
BZ LENGTHS2 ..
CLI 0(R1),C' ' if Mid(c,i,1)=" "
BNE LENGTHS2 then exit while
BCTR R1,0 @ci--
BCTR R0,0 i--
B LENGTHS1 endwhile
LENGTHS2 BR R14 return to caller
SS DC CL16'kitten',CL16'sitting'
DC CL16'rosettacode',CL16'raisethysword'
DC CL16'saturday',CL16'sunday'
DC CL16'sleep',CL16'fleeting'
NN DC A((NN-SS)/(2*L'SS))
N1 DS F n1
N2 DS F n2
S1 DS CL16 s1
S2 DS CL16 s2
D DS 256F d(16,16)
D1 DS F d1
D2 DS F d2
D3 DS F d3
C1 DS CL1 c1
C2 DS CL1 c2
PG DS CL80 buffer
XDEC DS CL12 temp fo xdeco
REGEQU
END LEVENS

View file

@ -0,0 +1,50 @@
# Calculate Levenshtein distance between strings - translated from the Action! sample #
BEGIN
PROC levenshtein distance = (STRING str1, str2)INT:
BEGIN
INT m=UPB str1;
INT n=UPB str2;
(0:m,0:n)INT matrix;
FOR i FROM 0 TO m DO FOR j FROM 0 TO n DO matrix(i,j):=0 OD OD;
FOR i TO m DO matrix(i,1):=i OD;
FOR j TO n DO matrix(1,j):=j OD;
FOR j FROM 1 TO n DO
FOR i FROM 1 TO m DO
IF str1(i) = str2(j) THEN
matrix(i,j):=matrix(i-1, j-1) # no operation required #
ELSE
INT min := matrix(i-1,j)+1 ; # deletion #
INT k = matrix(i,j-1)+1 ; # insertion #
INT l = matrix(i-1, j-1)+1 ; # substitution #
IF k < min THEN min:=k FI;
IF l < min THEN min:=l FI;
matrix(i,j):=min
FI
OD
OD;
matrix(m,n)
END;
STRING word 1, word 2;
word 1 :="kitten"; word 2 := "sitting";
print((word 1," -> ",word 2,": "));
print(("Levenshtein Distance: ",whole(levenshtein distance(word 1,word 2),0),newline));
word 1 := "rosettacode"; word 2 := "raisethysword";
print((word 1," -> ",word 2,": "));
print(("Levenshtein Distance: ",whole(levenshtein distance(word 1,word 2),0),newline));
word 1 := "qwerty"; word 2 := "qweryt";
print((word 1," -> ",word 2,": "));
print(("Levenshtein Distance: ",whole(levenshtein distance(word 1,word 2),0),newline));
word 1 := "Action!"; word 2 := "Algol 68";
print((word 1," -> ",word 2,": "));
print(("Levenshtein Distance: ",whole(levenshtein distance(word 1,word 2),0),newline))
END

View file

@ -0,0 +1,44 @@
#!/usr/bin/awk -f
BEGIN {
a = "kitten";
b = "sitting";
d = levenshteinDistance(a, b);
p = d == 1 ? "" : "s";
printf("%s -> %s after %d edit%s\n", a, b, d, p);
exit;
}
function levenshteinDistance(s1, s2,
s1First, s2First, s1Rest, s2Rest,
distA, distB, distC, minDist) {
# If either string is empty,
# then distance is insertion of the other's characters.
if (length(s1) == 0) return length(s2);
if (length(s2) == 0) return length(s1);
# Rest of process uses first characters
# and remainder of each string.
s1First = substr(s1, 1, 1);
s2First = substr(s2, 1, 1);
s1Rest = substr(s1, 2, length(s1));
s2Rest = substr(s2, 2, length(s2));
# If leading characters are the same,
# then distance is that between the rest of the strings.
if (s1First == s2First) {
return levenshteinDistance(s1Rest, s2Rest);
}
# Find the distances between sub strings.
distA = levenshteinDistance(s1Rest, s2);
distB = levenshteinDistance(s1, s2Rest);
distC = levenshteinDistance(s1Rest, s2Rest);
# Return the minimum distance between substrings.
minDist = distA;
if (distB < minDist) minDist = distB;
if (distC < minDist) minDist = distC;
return minDist + 1; # Include change for the first character.
}

View file

@ -0,0 +1,28 @@
#!/usr/bin/awk -f
function levdist(str1, str2, l1, l2, tog, arr, i, j, a, b, c) {
if (str1 == str2) {
return 0
} else if (str1 == "" || str2 == "") {
return length(str1 str2)
} else if (substr(str1, 1, 1) == substr(str2, 1, 1)) {
a = 2
while (substr(str1, a, 1) == substr(str2, a, 1)) a++
return levdist(substr(str1, a), substr(str2, a))
} else if (substr(str1, l1=length(str1), 1) == substr(str2, l2=length(str2), 1)) {
b = 1
while (substr(str1, l1-b, 1) == substr(str2, l2-b, 1)) b++
return levdist(substr(str1, 1, l1-b), substr(str2, 1, l2-b))
}
for (i = 0; i <= l2; i++) arr[0, i] = i
for (i = 1; i <= l1; i++) {
arr[tog = ! tog, 0] = i
for (j = 1; j <= l2; j++) {
a = arr[! tog, j ] + 1
b = arr[ tog, j-1] + 1
c = arr[! tog, j-1] + (substr(str1, i, 1) != substr(str2, j, 1))
arr[tog, j] = (((a<=b)&&(a<=c)) ? a : ((b<=a)&&(b<=c)) ? b : c)
}
}
return arr[tog, j-1]
}

View file

@ -0,0 +1,78 @@
DEFINE STRING="CHAR ARRAY" ; sys.act
DEFINE width="15" ; max characters 14
DEFINE MatrixSize="225" ; 15*15
PROC Set2Dm(INT ARRAY matrix, INT x,y, val)
matrix(x+y*width)=val
RETURN
INT FUNC Get2Dm(INT ARRAY matrix, INT x,y)
INT res
res=matrix(x+y*width)
RETURN(res)
INT FUNC DamerauLevenshteinDistance(STRING str1, str2)
INT ARRAY matrix(MatrixSize)
BYTE Result, tmp, Min, K, L, I, J, M, N
Result=0
M=str1(0)
N=str2(0)
FOR I=0 TO MatrixSize-1 DO matrix(I)=0 OD
FOR I=0 TO M DO Set2Dm(matrix, I,0, I) OD
FOR J=0 TO N DO Set2Dm(matrix, 0,J, J) OD
FOR J=1 TO N DO
FOR I=1 TO M DO
IF str1(I) = str2(J) THEN
tmp=Get2Dm(matrix, I-1, J-1)
Set2Dm(matrix, I,J, tmp) ; no operation required
ELSE
Min = Get2Dm(matrix, I-1,J)+1 ; REM delete
K = Get2Dm(matrix, I,J-1)+1 ; REM insert
L = Get2Dm(matrix, I-1, J-1)+1 ; REM substitution
IF K < Min THEN Min=K FI
IF L < Min THEN Min=L FI
Set2Dm(matrix, I,J, Min)
;transposition for Damerau Levenshtein Distance
;IF I>1 AND J>1 THEN
; IF str1(I) = str2(J-1) AND str1(I-1) = str2(J) THEN
; Min=Get2Dm(matrix, I,J)
; tmp=Get2Dm(matrix, I-2,J-2)+1
; IF Min>tmp THEN Min=tmp FI
; Set2Dm(matrix, I,J, Min) ; REM transposition
; FI
;FI
FI
OD
OD
Result=Get2Dm(matrix, M,N)
RETURN(Result)
PROC MAIN()
INT result
STRING Word_1(15), Word_2(15)
PUT(125)
PUTE()
SCopy(Word_1,"kitten") SCopy(Word_2,"sitting")
PrintF("%S - %S%E",Word_1,Word_2)
result=DamerauLevenshteinDistance(Word_1,Word_2)
PrintF("Levenshtein Distance=%U%E%E",result)
;PrintF("Damerau Levenshtein Distance=%U%E%E",result)
SCopy(Word_1,"rosettacode") SCopy(Word_2,"raisethysword")
PrintF("%S - %S%E",Word_1,Word_2)
result=DamerauLevenshteinDistance(Word_1,Word_2)
PrintF("Levenshtein Distance=%U%E%E",result)
;PrintF("Damerau Levenshtein Distance=%U%E%E",result)
SCopy(Word_1,"qwerty") SCopy(Word_2,"qweryt")
PrintF("%S - %S%E",Word_1,Word_2)
result=DamerauLevenshteinDistance(Word_1,Word_2)
PrintF("Levenshtein Distance=%U%E%E",result)
;PrintF("Damerau Levenshtein Distance=%U%E%E",result)
RETURN

View file

@ -0,0 +1,34 @@
with Ada.Text_IO;
procedure Main is
function Levenshtein_Distance (S, T : String) return Natural is
D : array (0 .. S'Length, 0 .. T'Length) of Natural;
begin
for I in D'Range (1) loop
D (I, 0) := I;
end loop;
for I in D'Range (2) loop
D (0, I) := I;
end loop;
for J in T'Range loop
for I in S'Range loop
if S (I) = T (J) then
D (I, J) := D (I - 1, J - 1);
else
D (I, J) :=
Natural'Min
(Natural'Min (D (I - 1, J) + 1, D (I, J - 1) + 1),
D (I - 1, J - 1) + 1);
end if;
end loop;
end loop;
return D (S'Length, T'Length);
end Levenshtein_Distance;
begin
Ada.Text_IO.Put_Line
("kitten -> sitting:" &
Integer'Image (Levenshtein_Distance ("kitten", "sitting")));
Ada.Text_IO.Put_Line
("rosettacode -> raisethysword:" &
Integer'Image (Levenshtein_Distance ("rosettacode", "raisethysword")));
end Main;

View file

@ -0,0 +1,45 @@
integer
dist(data s, t, integer i, j, list d)
{
integer x;
x = d[i * (~t + 1) + j];
if (x == -1) {
if (i == ~s) {
x = ~t - j;
} elif (j == ~t) {
x = ~s - i;
} elif (s[i] == t[j]) {
x = dist(s, t, i + 1, j + 1, d);
} else {
x = dist(s, t, i + 1, j + 1, d)
.min(dist(s, t, i, j + 1, d))
.min(dist(s, t, i + 1, j, d));
x += 1;
}
d[i * (~t + 1) + j] = x;
}
x;
}
levenshtein(data s, t)
{
list d;
d.pn_integer(0, (~s + 1) * (~t + 1), -1);
dist(s, t, 0, 0, d);
}
main(void)
{
text s1, s2;
o_form("`~' to `~' is ~\n", s1 = "rosettacode", s2 = "raisethysword",
levenshtein(s1, s2));
o_form("`~' to `~' is ~\n", s1 = "kitten", s2 = "sitting",
levenshtein(s1, s2));
0;
}

View file

@ -0,0 +1,55 @@
set dist to findLevenshteinDistance for "sunday" against "saturday"
to findLevenshteinDistance for s1 against s2
script o
property l : s1
property m : s2
end script
if s1 = s2 then return 0
set ll to length of s1
set lm to length of s2
if ll = 0 then return lm
if lm = 0 then return ll
set v0 to {}
repeat with i from 1 to (lm + 1)
set end of v0 to (i - 1)
end repeat
set item -1 of v0 to 0
copy v0 to v1
repeat with i from 1 to ll
-- calculate v1 (current row distances) from the previous row v0
-- first element of v1 is A[i+1][0]
-- edit distance is delete (i+1) chars from s to match empty t
set item 1 of v1 to i
-- use formula to fill in the rest of the row
repeat with j from 1 to lm
if item i of o's l = item j of o's m then
set cost to 0
else
set cost to 1
end if
set item (j + 1) of v1 to min3 for ((item j of v1) + 1) against ((item (j + 1) of v0) + 1) by ((item j of v0) + cost)
end repeat
copy v1 to v0
end repeat
return item (lm + 1) of v1
end findLevenshteinDistance
to min3 for anInt against anOther by theThird
if anInt < anOther then
if theThird < anInt then
return theThird
else
return anInt
end if
else
if theThird < anOther then
return theThird
else
return anOther
end if
end if
end min3

View file

@ -0,0 +1,154 @@
-- levenshtein :: String -> String -> Int
on levenshtein(sa, sb)
set {s1, s2} to {characters of sa, characters of sb}
script
on |λ|(ns, c)
script minPath
on |λ|(z, c1xy)
set {c1, x, y} to c1xy
minimum({y + 1, z + 1, x + fromEnum(c1 is not c)})
end |λ|
end script
set {n, ns1} to {item 1 of ns, rest of ns}
scanl(minPath, n + 1, zip3(s1, ns, ns1))
end |λ|
end script
last item of foldl(result, enumFromTo(0, length of s1), s2)
end levenshtein
--------------------------- TEST ---------------------------
on run
script test
on |λ|(tuple)
set {sa, sb} to tuple
levenshtein(sa, sb)
end |λ|
end script
map(test, [["kitten", "sitting"], ["sitting", "kitten"], ¬
["rosettacode", "raisethysword"], ["raisethysword", "rosettacode"]])
--> {3, 3, 8, 8}
end run
-------------------- GENERIC FUNCTIONS ---------------------
-- enumFromTo :: Int -> Int -> [Int]
on enumFromTo(m, n)
if m n then
set lst to {}
repeat with i from m to n
set end of lst to i
end repeat
lst
else
{}
end if
end enumFromTo
-- fromEnum :: Enum a => a -> Int
on fromEnum(x)
set c to class of x
if c is boolean then
if x then
1
else
0
end if
else if c is text then
if x "" then
id of x
else
missing value
end if
else
x as integer
end if
end fromEnum
-- foldl :: (a -> b -> a) -> a -> [b] -> a
on foldl(f, startValue, xs)
tell mReturn(f)
set v to startValue
set lng to length of xs
repeat with i from 1 to lng
set v to |λ|(v, item i of xs, i, xs)
end repeat
return v
end tell
end foldl
-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
-- The list obtained by applying f
-- to each element of xs.
tell mReturn(f)
set lng to length of xs
set lst to {}
repeat with i from 1 to lng
set end of lst to |λ|(item i of xs, i, xs)
end repeat
return lst
end tell
end map
-- minimum :: Ord a => [a] -> a
on minimum(xs)
set lng to length of xs
if lng < 1 then return missing value
set m to item 1 of xs
repeat with x in xs
set v to contents of x
if v < m then set m to v
end repeat
return m
end minimum
-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
-- 2nd class handler function lifted into 1st class script wrapper.
if script is class of f then
f
else
script
property |λ| : f
end script
end if
end mReturn
-- scanl :: (b -> a -> b) -> b -> [a] -> [b]
on scanl(f, startValue, xs)
tell mReturn(f)
set v to startValue
set lng to length of xs
set lst to {startValue}
repeat with i from 1 to lng
set v to |λ|(v, item i of xs, i, xs)
set end of lst to v
end repeat
return lst
end tell
end scanl
-- zip3 :: [a] -> [b] -> [c] -> [(a, b, c)]
on zip3(xs, ys, zs)
script
on |λ|(x, i)
{x, item i of ys, item i of zs}
end |λ|
end script
map(result, items 1 thru ¬
minimum({length of xs, length of ys, length of zs}) of xs)
end zip3

View file

@ -0,0 +1 @@
{3, 3, 8, 8}

View file

@ -0,0 +1,16 @@
(def levenshtein (str1 str2)
(withs l1 len.str1
l2 len.str2
row range0:inc.l1
(times j l2
(let next list.j
(times i l1
(push
(inc:min
car.next
((if (is str1.i str2.j) dec id) car.row)
(car:zap cdr row))
next))
(= row nrev.next)))
row.l1))

View file

@ -0,0 +1 @@
print levenshtein "kitten" "sitting"

View file

@ -0,0 +1,19 @@
levenshtein(s, t){
If s =
return StrLen(t)
If t =
return strLen(s)
If SubStr(s, 1, 1) = SubStr(t, 1, 1)
return levenshtein(SubStr(s, 2), SubStr(t, 2))
a := Levenshtein(SubStr(s, 2), SubStr(t, 2))
b := Levenshtein(s, SubStr(t, 2))
c := Levenshtein(SubStr(s, 2), t )
If (a > b)
a := b
if (a > c)
a := c
return a + 1
}
s1 := "kitten"
s2 := "sitting"
MsgBox % "distance between " s1 " and " s2 ": " levenshtein(s1, s2)

View file

@ -0,0 +1,28 @@
PRINT "'kitten' -> 'sitting' has distance " ;
PRINT ; FNlevenshtein("kitten", "sitting")
PRINT "'rosettacode' -> 'raisethysword' has distance " ;
PRINT ; FNlevenshtein("rosettacode", "raisethysword")
END
DEF FNlevenshtein(s$, t$)
LOCAL i%, j%, m%, d%()
DIM d%(LENs$, LENt$)
FOR i% = 0 TO DIM(d%(),1)
d%(i%,0) = i%
NEXT
FOR j% = 0 TO DIM(d%(),2)
d%(0,j%) = j%
NEXT
FOR j% = 1 TO DIM(d%(),2)
FOR i% = 1 TO DIM(d%(),1)
IF MID$(s$,i%,1) = MID$(t$,j%,1) THEN
d%(i%,j%) = d%(i%-1,j%-1)
ELSE
m% = d%(i%-1,j%-1)
IF d%(i%,j%-1) < m% m% = d%(i%,j%-1)
IF d%(i%-1,j%) < m% m% = d%(i%-1,j%)
d%(i%,j%) = m% + 1
ENDIF
NEXT
NEXT j%
= d%(i%-1,j%-1)

View file

@ -0,0 +1,7 @@
Levenshtein {
𝕨 𝕊"": 𝕨;
""𝕊 𝕩: 𝕩;
𝕨 𝕊 𝕩:
Tail1
𝕨 =1+·´ 𝕊Tail Tail𝕊 𝕊Tail, 𝕊Tail 𝕩
}

View file

@ -0,0 +1 @@
Levenshtein @{¯1(𝕨)𝕨{(1+`1+»+𝕨𝕗˙)𝕩}´𝕩}

View file

@ -0,0 +1,6 @@
"kitten" Levenshtein "sitting"
3
"Saturday" Levenshtein "Sunday"
3
"rosettacode" Levenshtein "raisethysword"
8

View file

@ -0,0 +1,25 @@
(levenshtein=
lev cache
. ( lev
= s s0 s1 t t0 t1 L a b c val key
. (cache..find)$(str$!arg:?key):(?.?val)
& !val
| !arg:(?s,?t)
& ( !s:&@(!t:? [?L)
| !t:&@(!s:? [?L)
)
& (cache..insert)$(!key.!L)
& !L
| !arg:(@(?:%?s0 ?s1),@(?:%?t0 ?t1))
& !s0:!t0
& lev$(!s1,!t1)
| lev$(!s1,!t1):?a
& lev$(!s,!t1):?b
& lev$(!s1,!t):?c
& (!b:<!a:?a|)
& (!c:<!a:?a|)
& (cache..insert)$(!key.1+!a)
& 1+!a
)
& new$hash:?cache
& lev$!arg);

View file

@ -0,0 +1,55 @@
#include <string>
#include <iostream>
using namespace std;
// Compute Levenshtein Distance
// Martin Ettl, 2012-10-05
size_t uiLevenshteinDistance(const string &s1, const string &s2)
{
const size_t
m(s1.size()),
n(s2.size());
if( m==0 ) return n;
if( n==0 ) return m;
// allocation below is not ISO-compliant,
// it won't work with -pedantic-errors.
size_t costs[n + 1];
for( size_t k=0; k<=n; k++ ) costs[k] = k;
size_t i { 0 };
for (char const &c1 : s1)
{
costs[0] = i+1;
size_t corner { i },
j { 0 };
for (char const &c2 : s2)
{
size_t upper { costs[j+1] };
if( c1 == c2 ) costs[j+1] = corner;
else {
size_t t(upper<corner? upper: corner);
costs[j+1] = (costs[j]<t?costs[j]:t)+1;
}
corner = upper;
j++;
}
i++;
}
return costs[n];
}
int main()
{
string s0 { "rosettacode" },
s1 { "raisethysword" };
cout << "distance between " << s0 << " and " << s1 << " : "
<< uiLevenshteinDistance(s0,s1) << endl;
return 0;
}

View file

@ -0,0 +1,40 @@
#include <algorithm>
#include <iostream>
#include <numeric>
#include <string>
#include <vector>
template <typename StringType>
size_t levenshtein_distance(const StringType& s1, const StringType& s2) {
const size_t m = s1.size();
const size_t n = s2.size();
if (m == 0)
return n;
if (n == 0)
return m;
std::vector<size_t> costs(n + 1);
std::iota(costs.begin(), costs.end(), 0);
size_t i = 0;
for (auto c1 : s1) {
costs[0] = i + 1;
size_t corner = i;
size_t j = 0;
for (auto c2 : s2) {
size_t upper = costs[j + 1];
costs[j + 1] = (c1 == c2) ? corner
: 1 + std::min(std::min(upper, corner), costs[j]);
corner = upper;
++j;
}
++i;
}
return costs[n];
}
int main() {
std::wstring s0 = L"rosettacode";
std::wstring s1 = L"raisethysword";
std::wcout << L"distance between " << s0 << L" and " << s1 << L": "
<< levenshtein_distance(s0, s1) << std::endl;
return 0;
}

View file

@ -0,0 +1,50 @@
using System;
namespace LevenshteinDistance
{
class Program
{
static int LevenshteinDistance(string s, string t)
{
int n = s.Length;
int m = t.Length;
int[,] d = new int[n + 1, m + 1];
if (n == 0)
{
return m;
}
if (m == 0)
{
return n;
}
for (int i = 0; i <= n; i++)
d[i, 0] = i;
for (int j = 0; j <= m; j++)
d[0, j] = j;
for (int j = 1; j <= m; j++)
for (int i = 1; i <= n; i++)
if (s[i - 1] == t[j - 1])
d[i, j] = d[i - 1, j - 1]; //no operation
else
d[i, j] = Math.Min(Math.Min(
d[i - 1, j] + 1, //a deletion
d[i, j - 1] + 1), //an insertion
d[i - 1, j - 1] + 1 //a substitution
);
return d[n, m];
}
static void Main(string[] args)
{
if (args.Length == 2)
Console.WriteLine("{0} -> {1} = {2}",
args[0], args[1], LevenshteinDistance(args[0], args[1]));
else
Console.WriteLine("Usage:-\n\nLevenshteinDistance <string1> <string2>");
}
}
}

View file

@ -0,0 +1,45 @@
#include <stdio.h>
#include <string.h>
/* s, t: two strings; ls, lt: their respective length */
int levenshtein(const char *s, int ls, const char *t, int lt)
{
int a, b, c;
/* if either string is empty, difference is inserting all chars
* from the other
*/
if (!ls) return lt;
if (!lt) return ls;
/* if last letters are the same, the difference is whatever is
* required to edit the rest of the strings
*/
if (s[ls - 1] == t[lt - 1])
return levenshtein(s, ls - 1, t, lt - 1);
/* else try:
* changing last letter of s to that of t; or
* remove last letter of s; or
* remove last letter of t,
* any of which is 1 edit plus editing the rest of the strings
*/
a = levenshtein(s, ls - 1, t, lt - 1);
b = levenshtein(s, ls, t, lt - 1);
c = levenshtein(s, ls - 1, t, lt );
if (a > b) a = b;
if (a > c) a = c;
return a + 1;
}
int main()
{
const char *s1 = "rosettacode";
const char *s2 = "raisethysword";
printf("distance between `%s' and `%s': %d\n", s1, s2,
levenshtein(s1, strlen(s1), s2, strlen(s2)));
return 0;
}

View file

@ -0,0 +1,44 @@
#include <stdio.h>
#include <string.h>
int levenshtein(const char *s, const char *t)
{
int ls = strlen(s), lt = strlen(t);
int d[ls + 1][lt + 1];
for (int i = 0; i <= ls; i++)
for (int j = 0; j <= lt; j++)
d[i][j] = -1;
int dist(int i, int j) {
if (d[i][j] >= 0) return d[i][j];
int x;
if (i == ls)
x = lt - j;
else if (j == lt)
x = ls - i;
else if (s[i] == t[j])
x = dist(i + 1, j + 1);
else {
x = dist(i + 1, j + 1);
int y;
if ((y = dist(i, j + 1)) < x) x = y;
if ((y = dist(i + 1, j)) < x) x = y;
x++;
}
return d[i][j] = x;
}
return dist(0, 0);
}
int main(void)
{
const char *s1 = "rosettacode";
const char *s2 = "raisethysword";
printf("distance between `%s' and `%s': %d\n", s1, s2,
levenshtein(s1, s2));
return 0;
}

View file

@ -0,0 +1,44 @@
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
levenshtein = proc (s, t: string) returns (int)
ai = array[int]
aai = array[array[int]]
m: int := string$size(s)
n: int := string$size(t)
d: aai := aai$fill_copy(0, m+1, ai$fill(0, n+1, 0))
for i: int in int$from_to(1, m) do d[i][0] := i end
for j: int in int$from_to(1, n) do d[0][j] := j end
for j: int in int$from_to(1, n) do
for i: int in int$from_to(1, m) do
cost: int
if s[i] = t[j]
then cost := 0
else cost := 1
end
d[i][j] := min[int]( d[i-1][j]+1,
min[int]( d[i][j-1]+1,
d[i-1][j-1]+cost ))
end
end
return (d[m][n])
end levenshtein
show = proc (s, t: string)
po: stream := stream$primary_output()
stream$putl(po, s || " => " || t || ": " || int$unparse(levenshtein(s,t)))
end show
start_up = proc ()
show("kitten", "sitting")
show("rosettacode", "raisethysword")
end start_up

View file

@ -0,0 +1,62 @@
identification division.
program-id. Levenshtein.
environment division.
configuration section.
repository.
function all intrinsic.
data division.
working-storage section.
77 string-a pic x(255).
77 string-b pic x(255).
77 length-a pic 9(3).
77 length-b pic 9(3).
77 distance pic z(3).
77 i pic 9(3).
77 j pic 9(3).
01 tab.
05 filler occurs 256.
10 filler occurs 256.
15 costs pic 9(3).
procedure division.
main.
move "kitten" to string-a
move "sitting" to string-b
perform levenshtein-dist
move "rosettacode" to string-a
move "raisethysword" to string-b
perform levenshtein-dist
stop run
.
levenshtein-dist.
move length(trim(string-a)) to length-a
move length(trim(string-b)) to length-b
initialize tab
perform varying i from 0 by 1 until i > length-a
move i to costs(i + 1, 1)
end-perform
perform varying j from 0 by 1 until j > length-b
move j to costs(1, j + 1)
end-perform
perform with test after varying i from 2 by 1 until i > length-a
perform with test after varying j from 2 by 1 until j > length-b
if string-a(i - 1:1) = string-b(j - 1:1)
move costs(i - 1, j - 1) to costs(i, j)
else
move min(min(costs(i - 1, j) + 1, *> a deletion
costs(i, j - 1) + 1), *> an insertion
costs(i - 1, j - 1) + 1) *> a substitution
to costs(i, j)
end-if
end-perform
end-perform
move costs(length-a + 1, length-b + 1) to distance
display trim(string-a) " -> " trim(string-b) " = " trim(distance)
.

View file

@ -0,0 +1,13 @@
(defn levenshtein [str1 str2]
(let [len1 (count str1)
len2 (count str2)]
(cond (zero? len1) len2
(zero? len2) len1
:else
(let [cost (if (= (first str1) (first str2)) 0 1)]
(min (inc (levenshtein (rest str1) str2))
(inc (levenshtein str1 (rest str2)))
(+ cost
(levenshtein (rest str1) (rest str2))))))))
(println (levenshtein "rosettacode" "raisethysword"))

View file

@ -0,0 +1,21 @@
(defn levenshtein [w1 w2]
(letfn [(cell-value [same-char? prev-row cur-row col-idx]
(min (inc (nth prev-row col-idx))
(inc (last cur-row))
(+ (nth prev-row (dec col-idx)) (if same-char?
0
1))))]
(loop [row-idx 1
max-rows (inc (count w2))
prev-row (range (inc (count w1)))]
(if (= row-idx max-rows)
(last prev-row)
(let [ch2 (nth w2 (dec row-idx))
next-prev-row (reduce (fn [cur-row i]
(let [same-char? (= (nth w1 (dec i)) ch2)]
(conj cur-row (cell-value same-char?
prev-row
cur-row
i))))
[row-idx] (range 1 (count prev-row)))]
(recur (inc row-idx) max-rows next-prev-row))))))

View file

@ -0,0 +1,30 @@
levenshtein = (str1, str2) ->
# more of less ported simple algorithm from JS
m = str1.length
n = str2.length
d = []
return n unless m
return m unless n
d[i] = [i] for i in [0..m]
d[0][j] = j for j in [1..n]
for i in [1..m]
for j in [1..n]
if str1[i-1] is str2[j-1]
d[i][j] = d[i-1][j-1]
else
d[i][j] = Math.min(
d[i-1][j]
d[i][j-1]
d[i-1][j-1]
) + 1
d[m][n]
console.log levenshtein("kitten", "sitting")
console.log levenshtein("rosettacode", "raisethysword")
console.log levenshtein("stop", "tops")
console.log levenshtein("yo", "")
console.log levenshtein("", "yo")

View file

@ -0,0 +1,16 @@
(defun levenshtein (a b)
(let* ((la (length a))
(lb (length b))
(rec (make-array (list (1+ la) (1+ lb)) :initial-element nil)))
(labels ((leven (x y)
(cond
((zerop x) y)
((zerop y) x)
((aref rec x y) (aref rec x y))
(t (setf (aref rec x y)
(min (+ (leven (1- x) y) 1)
(+ (leven x (1- y)) 1)
(+ (leven (1- x) (1- y)) (if (char= (char a (- la x)) (char b (- lb y))) 0 1))))))))
(leven la lb))))
(print (levenshtein "rosettacode" "raisethysword"))

View file

@ -0,0 +1,3 @@
require "levenshtein"
puts Levenshtein.distance("kitten", "sitting")
puts Levenshtein.distance("rosettacode", "raisethysword")

View file

@ -0,0 +1,23 @@
module Levenshtein
def self.distance(a, b)
a, b = a.downcase, b.downcase
costs = (0..b.size).to_a
(1..a.size).each do |i|
costs[0], nw = i, i - 1 # j == 0; nw is lev(i-1, j)
(1..b.size).each do |j|
costs[j], nw = [costs[j] + 1, costs[j-1] + 1, a[i-1] == b[j-1] ? nw : nw + 1].min, costs[j]
end
end
costs[b.size]
end
def self.test
%w{kitten sitting saturday sunday rosettacode raisethysword}.each_slice(2) do |(a, b)| #or do |pair| a, b = pair
puts "distance(#{a}, #{b}) = #{distance(a, b)}"
end
end
end
Levenshtein.test

View file

@ -0,0 +1,31 @@
def levenshtein_distance(str1, str2)
n, m = str1.size, str2.size
max = n / 2
return 0 if n == 0 || m == 0
return n if (n - m).abs > max
d = (0..m).to_a
x = 0
str1.each_char_with_index do |char1, i|
e = i + 1
str2.each_char_with_index do |char2, j|
cost = (char1 == char2) ? 0 : 1
x = [ d[j+1] + 1, # insertion
e + 1, # deletion
d[j] + cost # substitution
].min
d[j] = e
e = x
end
d[m] = x
end
x
end
%w{kitten sitting saturday sunday rosettacode raisethysword}.each_slice(2) do |(a, b)| #or do |pair| a, b = pair
puts "distance(#{a}, #{b}) = #{levenshtein_distance(a, b)}"
end

View file

@ -0,0 +1,5 @@
void main() {
import std.stdio, std.algorithm;
levenshteinDistance("kitten", "sitting").writeln;
}

View file

@ -0,0 +1,32 @@
import std.stdio, std.algorithm;
int distance(in string s1, in string s2) pure nothrow {
auto costs = new int[s2.length + 1];
foreach (immutable i; 0 .. s1.length + 1) {
int lastValue = i;
foreach (immutable j; 0 .. s2.length + 1) {
if (i == 0)
costs[j] = j;
else {
if (j > 0) {
int newValue = costs[j - 1];
if (s1[i - 1] != s2[j - 1])
newValue = min(newValue, lastValue, costs[j]) + 1;
costs[j - 1] = lastValue;
lastValue = newValue;
}
}
}
if (i > 0)
costs[$ - 1] = lastValue;
}
return costs[$ - 1];
}
void main() {
foreach (p; [["kitten", "sitting"], ["rosettacode", "raisethysword"]])
writefln("distance(%s, %s): %d", p[0], p[1], distance(p[0], p[1]));
}

View file

@ -0,0 +1,15 @@
import std.stdio, std.array, std.algorithm, std.functional;
uint lDist(T)(in const(T)[] s, in const(T)[] t) nothrow {
alias mlDist = memoize!lDist;
if (s.empty || t.empty) return max(t.length, s.length);
if (s[0] == t[0]) return mlDist(s[1 .. $], t[1 .. $]);
return min(mlDist(s, t[1 .. $]),
mlDist(s[1 .. $], t),
mlDist(s[1 .. $], t[1 .. $])) + 1;
}
void main() {
lDist("kitten", "sitting").writeln;
lDist("rosettacode", "raisethysword").writeln;
}

View file

@ -0,0 +1,23 @@
function LevenshteinDistance(s, t : String) : Integer;
var
i, j : Integer;
begin
var d:=new Integer[Length(s)+1, Length(t)+1];
for i:=0 to Length(s) do
d[i, 0] := i;
for j:=0 to Length(t) do
d[0, j] := j;
for j:=1 to Length(t) do
for i:=1 to Length(s) do
if s[i]=t[j] then
d[i, j] := d[i-1, j-1] // no operation
else d[i,j]:=MinInt(MinInt(
d[i-1, j] +1 , // a deletion
d[i, j-1] +1 ), // an insertion
d[i- 1,j-1] +1 // a substitution
);
Result:=d[Length(s), Length(t)];
end;
PrintLn(LevenshteinDistance('kitten', 'sitting'));

View file

@ -0,0 +1,63 @@
program Levenshtein_distanceTest;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
Math;
function Levenshtein_distance(s, t: string): integer;
var
d: array of array of integer;
i, j, cost: integer;
begin
SetLength(d, Length(s) + 1);
for i := Low(d) to High(d) do
begin
SetLength(d[i], Length(t) + 1);
end;
for i := Low(d) to High(d) do
begin
d[i, 0] := i;
for j := Low(d[i]) to High(d[i]) do
begin
d[0, j] := j;
end;
end;
for i := Low(d) + 1 to High(d) do
begin
for j := Low(d[i]) + 1 to High(d[i]) do
begin
if s[i] = t[j] then
begin
cost := 0;
end
else
begin
cost := 1;
end;
d[i, j] := Min(Min(d[i - 1, j] + 1, //deletion
d[i, j - 1] + 1), //insertion
d[i - 1, j - 1] + cost //substitution
);
end;
end;
Result := d[Length(s), Length(t)];
end;
procedure Println(s, t: string);
begin
Writeln('> LevenshteinDistance "', s, '" "', t, '"');
Writeln(s, ' -> ', t, ' = ', Levenshtein_distance(s, t), #10);
end;
begin
Println('kitten', 'sitting');
Println('rosettacode', 'raisethysword');
readln;
end.

View file

@ -0,0 +1,44 @@
func levenshtein(s, t) {
var n = s.Length()
var m = t.Length()
var d = Array.Empty(n + 1, () => Array.Empty(m + 1))
if n == 0 {
return m
}
if (m == 0) {
return n
}
for i in 0..n {
d[i][0] = i
}
for j in 0..m {
d[0][j] = j
}
for j in 1..m {
for i in 1..n {
if s[i - 1] == t[j - 1] {
d[i][j] = d[i - 1][j - 1] //no operation
}
else {
d[i][j] = min(min(
d[i - 1][j] + 1, //a deletion
d[i][j - 1] + 1), //an insertion
d[i - 1][j - 1] + 1 //a substitution
)
}
}
}
d[n][m]
}
func run(x, y) {
print("\(x) -> \(y) = \(levenshtein(x, y))")
}
run("rosettacode", "raisethysword")

View file

@ -0,0 +1,43 @@
PROGRAM LEVENSHTEIN
!$DYNAMIC
DIM D%[0,0]
PROCEDURE LEVENSHTEIN(S$,T$->RES%)
LOCAL I%,J%,M%
FOR I%=0 TO LEN(S$) DO
D%[I%,0]=I%
END FOR
FOR J%=0 TO LEN(T$) DO
D%[0,J%]=J%
END FOR
FOR J%=1 TO LEN(T$) DO
FOR I%=1 TO LEN(S$) DO
IF MID$(S$,I%,1)=MID$(T$,J%,1) THEN
D%[I%,J%]=D%[I%-1,J%-1]
ELSE
M%=D%[I%-1,J%-1]
IF D%[I%,J%-1]<M% THEN M%=D%[I%,J%-1] END IF
IF D%[I%-1,J%]<M% THEN M%=D%[I%-1,J%] END IF
D%[I%,J%]=M%+1
END IF
END FOR
END FOR
RES%=D%[I%-1,J%-1]
END PROCEDURE
BEGIN
S$="kitten" T$="sitting"
PRINT("'";S$;"' -> '";T$;"' has distance ";)
!$DIM D%[LEN(S$),LEN(T$)]
LEVENSHTEIN(S$,T$->RES%)
PRINT(RES%)
!$ERASE D%
S$="rosettacode" T$="raisethysword"
PRINT("'";S$;"' -> '";T$;"' has distance ";)
!$DIM D%[LEN(S$),LEN(T$)]
LEVENSHTEIN(S$,T$->RES%)
PRINT(RES%)
!$ERASE D%
END PROGRAM

View file

@ -0,0 +1,28 @@
;; Recursive version adapted from Clojure
;; Added necessary memoization
(define (levenshtein str1 str2 (cost 0) (rest1 0) (rest2 0) (key null))
(set! key (string-append str1 "|" str2))
(if (get 'mem key) ;; memoized ?
(get 'mem key)
;; else memoize
(putprop 'mem
(let [(len1 (string-length str1))
(len2 (string-length str2))]
(cond ((zero? len1) len2)
((zero? len2) len1)
(else
(set! cost (if (= (string-first str1) (string-first str2)) 0 1))
(set! rest1 (string-rest str1))
(set! rest2 (string-rest str2))
(min (1+ (levenshtein rest1 str2))
(1+ (levenshtein str1 rest2))
(+ cost
(levenshtein rest1 rest2 ))))))
key)))
;; 😛 127 calls with memoization
;; 😰 29737 calls without memoization
(levenshtein "kitten" "sitting") → 3
(levenshtein "rosettacode" "raisethysword") → 8

View file

@ -0,0 +1,5 @@
open list
levenshtein s1 s2 = last <| foldl transform [0 .. length s1] s2
where transform (n::ns')@ns c = scanl calc (n+1) <| zip3 s1 ns ns'
where calc z (c', x, y) = minimum [y+1, z+1, x + toInt (c' <> c)]

View file

@ -0,0 +1 @@
(levenshtein "kitten" "sitting", levenshtein "rosettacode" "raisethysword")

View file

@ -0,0 +1,28 @@
defmodule Levenshtein do
def distance(a, b) do
ta = String.downcase(a) |> to_charlist |> List.to_tuple
tb = String.downcase(b) |> to_charlist |> List.to_tuple
m = tuple_size(ta)
n = tuple_size(tb)
costs = Enum.reduce(0..m, %{}, fn i,acc -> Map.put(acc, {i,0}, i) end)
costs = Enum.reduce(0..n, costs, fn j,acc -> Map.put(acc, {0,j}, j) end)
Enum.reduce(0..n-1, costs, fn j, acc ->
Enum.reduce(0..m-1, acc, fn i, map ->
d = if elem(ta, i) == elem(tb, j) do
map[ {i,j} ]
else
Enum.min([ map[ {i , j+1} ] + 1, # deletion
map[ {i+1, j } ] + 1, # insertion
map[ {i , j } ] + 1 ]) # substitution
end
Map.put(map, {i+1, j+1}, d)
end)
end)
|> Map.get({m,n})
end
end
words = ~w(kitten sitting saturday sunday rosettacode raisethysword)
Enum.each(Enum.chunk(words, 2), fn [a,b] ->
IO.puts "distance(#{a}, #{b}) = #{Levenshtein.distance(a,b)}"
end)

View file

@ -0,0 +1,35 @@
-module(levenshtein).
-compile(export_all).
distance_cached(S,T) ->
{L,_} = ld(S,T,dict:new()),
L.
distance(S,T) ->
ld(S,T).
ld([],T) ->
length(T);
ld(S,[]) ->
length(S);
ld([X|S],[X|T]) ->
ld(S,T);
ld([_SH|ST]=S,[_TH|TT]=T) ->
1 + lists:min([ld(S,TT),ld(ST,T),ld(ST,TT)]).
ld([]=S,T,Cache) ->
{length(T),dict:store({S,T},length(T),Cache)};
ld(S,[]=T,Cache) ->
{length(S),dict:store({S,T},length(S),Cache)};
ld([X|S],[X|T],Cache) ->
ld(S,T,Cache);
ld([_SH|ST]=S,[_TH|TT]=T,Cache) ->
case dict:is_key({S,T},Cache) of
true -> {dict:fetch({S,T},Cache),Cache};
false ->
{L1,C1} = ld(S,TT,Cache),
{L2,C2} = ld(ST,T,C1),
{L3,C3} = ld(ST,TT,C2),
L = 1+lists:min([L1,L2,L3]),
{L,dict:store({S,T},L,C3)}
end.

View file

@ -0,0 +1,8 @@
68> timer:tc(levenshtein,distance,["rosettacode","raisethysword"]).
{774799,8} % {Time, Result}
69> timer:tc(levenshtein,distance_cached,["rosettacode","raisethysword"]).
{659,8}
70> timer:tc(levenshtein,distance,["kitten","sitting"]).
{216,3}
71> timer:tc(levenshtein,distance_cached,["kitten","sitting"]).
{213,3}

View file

@ -0,0 +1,47 @@
function min(sequence s)
atom m
m = s[1]
for i = 2 to length(s) do
if s[i] < m then
m = s[i]
end if
end for
return m
end function
function levenshtein(sequence s1, sequence s2)
integer n, m
sequence d
n = length(s1) + 1
m = length(s2) + 1
if n = 1 then
return m-1
elsif m = 1 then
return n-1
end if
d = repeat(repeat(0, m), n)
for i = 1 to n do
d[i][1] = i-1
end for
for j = 1 to m do
d[1][j] = j-1
end for
for i = 2 to n do
for j = 2 to m do
d[i][j] = min({
d[i-1][j] + 1,
d[i][j-1] + 1,
d[i-1][j-1] + (s1[i-1] != s2[j-1])
})
end for
end for
return d[n][m]
end function
? levenshtein("kitten", "sitting")
? levenshtein("rosettacode", "raisethysword")

View file

@ -0,0 +1,32 @@
open System
let getInput (name : string) =
Console.Write ("String {0}: ", name)
Console.ReadLine ()
let levDist (strOne : string) (strTwo : string) =
let strOne = strOne.ToCharArray ()
let strTwo = strTwo.ToCharArray ()
let (distArray : int[,]) = Array2D.zeroCreate (strOne.Length + 1) (strTwo.Length + 1)
for i = 0 to strOne.Length do distArray.[i, 0] <- i
for j = 0 to strTwo.Length do distArray.[0, j] <- j
for j = 1 to strTwo.Length do
for i = 1 to strOne.Length do
if strOne.[i - 1] = strTwo.[j - 1] then distArray.[i, j] <- distArray.[i - 1, j - 1]
else
distArray.[i, j] <- List.min (
[distArray.[i-1, j] + 1;
distArray.[i, j-1] + 1;
distArray.[i-1, j-1] + 1]
)
distArray.[strOne.Length, strTwo.Length]
let stringOne = getInput "One"
let stringTwo = getInput "Two"
printf "%A" (levDist stringOne stringTwo)
Console.ReadKey () |> ignore

View file

@ -0,0 +1,22 @@
open System
let levenshtein (s1:string) (s2:string) : int =
let s1' = s1.ToCharArray()
let s2' = s2.ToCharArray()
let rec dist l1 l2 =
match (l1,l2) with
| (l1, 0) -> l1
| (0, l2) -> l2
| (l1, l2) ->
if s1'.[l1-1] = s2'.[l2-1] then dist (l1-1) (l2-1)
else
let d1 = dist (l1 - 1) l2
let d2 = dist l1 (l2 - 1)
let d3 = dist (l1 - 1) (l2 - 1)
1 + Math.Min(d1,(Math.Min(d2,d3)))
dist s1.Length s2.Length
printfn "dist(kitten, sitting) = %i" (levenshtein "kitten" "sitting")

View file

@ -0,0 +1,2 @@
USING: lcs prettyprint ;
"kitten" "sitting" levenshtein .

View file

@ -0,0 +1,23 @@
: levenshtein ( a1 n1 a2 n2 -- n3)
dup \ if either string is empty, difference
if \ is inserting all chars from the other
2>r dup
if
2dup 1- chars + c@ 2r@ 1- chars + c@ =
if
1- 2r> 1- recurse exit
else \ else try:
2dup 1- 2r@ 1- recurse -rot \ changing first letter of s to t;
2dup 2r@ 1- recurse -rot \ remove first letter of s;
1- 2r> recurse min min 1+ \ remove first letter of t,
then \ any of which is 1 edit plus
else \ editing the rest of the strings
2drop 2r> nip
then
else
2drop nip
then
;
s" kitten" s" sitting" levenshtein . cr
s" rosettacode" s" raisethysword" levenshtein . cr

View file

@ -0,0 +1,38 @@
program demo_edit_distance
character(len=:),allocatable :: sources(:),targets(:)
integer,allocatable :: answers(:),expected(:)
sources=[character(len=20) :: "kitten", "rosettacode", "Saturday", "sleep", "qwerty", "Fortran" ]
targets=[character(len=20) :: "sitting", "raisethysword", "Sunday", "fleeting", "qweryt", "Fortran" ]
expected=[ 3, 8, 3, 5, 2, 0 ]
! calculate answers
answers=edit_distance(sources,targets)
! print inputs, answers, and confirmation
do i=1, size(sources)
write(*,'(*(g0,1x))') sources(i), targets(i), answers(i), answers(i) == expected(i)
enddo
! a longer test
write(*,*)edit_distance("here's a bunch of words", "to wring out this code")==18
contains
pure elemental integer function edit_distance (source,target)
!! The Levenshtein distance function returns how many edits (deletions,
!! insertions, transposition) are required to turn one string into another.
character(len=*), intent(in) :: source, target
integer :: len_source, len_target, i, j, cost
integer :: matrix(0:len_trim(source), 0:len_trim(target))
len_source = len_trim(source)
len_target = len_trim(target)
matrix(:,0) = [(i,i=0,len_source)]
matrix(0,:) = [(j,j=0,len_target)]
do i = 1, len_source
do j = 1, len_target
cost=merge(0,1,source(i:i)==target(j:j))
matrix(i,j) = min(matrix(i-1,j)+1, matrix(i,j-1)+1, matrix(i-1,j-1)+cost)
enddo
enddo
edit_distance = matrix(len_source,len_target)
end function edit_distance
end program demo_edit_distance

View file

@ -0,0 +1,49 @@
' FB 1.05.0 Win64
' Uses the "iterative with two matrix rows" algorithm
' referred to in the Wikipedia article.
Function min(x As Integer, y As Integer) As Integer
Return IIf(x < y, x, y)
End Function
Function levenshtein(s As String, t As String) As Integer
' degenerate cases
If s = t Then Return 0
If s = "" Then Return Len(t)
If t = "" Then Return Len(s)
' create two integer arrays of distances
Dim v0(0 To Len(t)) As Integer '' previous
Dim v1(0 To Len(t)) As Integer '' current
' initialize v0
For i As Integer = 0 To Len(t)
v0(i) = i
Next
Dim cost As Integer
For i As Integer = 0 To Len(s) - 1
' calculate v1 from v0
v1(0) = i + 1
For j As Integer = 0 To Len(t) - 1
cost = IIf(s[i] = t[j], 0, 1)
v1(j + 1) = min(v1(j) + 1, min(v0(j + 1) + 1, v0(j) + cost))
Next j
' copy v1 to v0 for next iteration
For j As Integer = 0 To Len(t)
v0(j) = v1(j)
Next j
Next i
Return v1(Len(t))
End Function
Print "'kitten' to 'sitting' => "; levenshtein("kitten", "sitting")
Print "'rosettacode' to 'raisethysword' => "; levenshtein("rosettacode", "raisethysword")
Print "'sleep' to 'fleeting' => "; levenshtein("sleep", "fleeting")
Print
Print "Press any key to quit"
Sleep

View file

@ -0,0 +1 @@
println[editDistance["kitten","sitting"]]

View file

@ -0,0 +1,51 @@
local fn LevenshteinDistance( s1 as CFStringRef, s2 as CFStringRef ) as NSInteger
NSInteger result
// If strings are equal, Levenshtein distance is 0
if ( fn StringIsEqual( s1, s2 ) ) then result = 0 : exit fn
// If either string is empty, then distance is the length of the other string.
if ( len(s1) == 0) then result = len(s2) : exit fn
if ( len(s2) == 0) then result = len(s1) : exit fn
// The remaining recursive process uses first characters and remainder of each string.
CFStringRef s1First = fn StringSubstringToIndex( s1, 1 )
CFStringRef s2First = fn StringSubstringToIndex( s2, 1 )
CFStringRef s1Rest = mid( s1, 1, len(s1) -1 )
CFStringRef s2Rest = mid( s2, 1, len(s2) -1 )
// If leading characters are the same, then distance is that between the rest of the strings.
if fn StringIsEqual( s1First, s2First ) then result = fn LevenshteinDistance( s1Rest, s2Rest ) : exit fn
// Find the distances between sub strings.
NSInteger distA = fn LevenshteinDistance( s1Rest, s2 )
NSInteger distB = fn LevenshteinDistance( s1, s2Rest )
NSInteger distC = fn LevenshteinDistance( s1Rest, s2Rest )
// Return the minimum distance between substrings.
NSInteger minDist = distA
if ( distB < minDist ) then minDist = distB
if ( distC < minDist ) then minDist = distC
result = minDist + 1 // Include change for the first character.
end fn = result
NSInteger i
CFStringRef testStr( 6, 2 )
testStr( 0, 0 ) = @"kitten" : testStr( 0, 1 ) = @"sitting"
testStr( 1, 0 ) = @"rosettacode" : testStr( 1, 1 ) = @"raisethysword"
testStr( 2, 0 ) = @"Saturday" : testStr( 2, 1 ) = @"Sunday"
testStr( 3, 0 ) = @"FutureBasic" : testStr( 3, 1 ) = @"FutureBasic"
testStr( 4, 0 ) = @"rave" : testStr( 4, 1 ) = @"ravel"
testStr( 5, 0 ) = @"black" : testStr( 5, 1 ) = @"slack"
testStr( 6, 0 ) = @"rave" : testStr( 6, 1 ) = @"grave"
for i = 0 to 6
print @"1st string = "; testStr( i, 0 )
print @"2nd string = "; testStr( i, 1 )
print @"Levenshtein distance = "; fn LevenshteinDistance( testStr( i, 0 ), testStr( i, 1 ) )
print
next
HandleEvents

View file

@ -0,0 +1,38 @@
package main
import "fmt"
func main() {
fmt.Println(ld("kitten", "sitting"))
}
func ld(s, t string) int {
d := make([][]int, len(s)+1)
for i := range d {
d[i] = make([]int, len(t)+1)
}
for i := range d {
d[i][0] = i
}
for j := range d[0] {
d[0][j] = j
}
for j := 1; j <= len(t); j++ {
for i := 1; i <= len(s); i++ {
if s[i-1] == t[j-1] {
d[i][j] = d[i-1][j-1]
} else {
min := d[i-1][j]
if d[i][j-1] < min {
min = d[i][j-1]
}
if d[i-1][j-1] < min {
min = d[i-1][j-1]
}
d[i][j] = min + 1
}
}
}
return d[len(s)][len(t)]
}

View file

@ -0,0 +1,24 @@
package main
import "fmt"
func levenshtein(s, t string) int {
if s == "" { return len(t) }
if t == "" { return len(s) }
if s[0] == t[0] {
return levenshtein(s[1:], t[1:])
}
a := levenshtein(s[1:], t[1:])
b := levenshtein(s, t[1:])
c := levenshtein(s[1:], t)
if a > b { a = b }
if a > c { a = c }
return a + 1
}
func main() {
s1 := "rosettacode"
s2 := "raisethysword"
fmt.Printf("distance between %s and %s: %d\n", s1, s2,
levenshtein(s1, s2))
}

View file

@ -0,0 +1,19 @@
def distance(String str1, String str2) {
def dist = new int[str1.size() + 1][str2.size() + 1]
(0..str1.size()).each { dist[it][0] = it }
(0..str2.size()).each { dist[0][it] = it }
(1..str1.size()).each { i ->
(1..str2.size()).each { j ->
dist[i][j] = [dist[i - 1][j] + 1, dist[i][j - 1] + 1, dist[i - 1][j - 1] + ((str1[i - 1] == str2[j - 1]) ? 0 : 1)].min()
}
}
return dist[str1.size()][str2.size()]
}
[ ['kitten', 'sitting']: 3,
['rosettacode', 'raisethysword']: 8,
['edocattesor', 'drowsyhtesiar']: 8 ].each { key, dist ->
println "Checking distance(${key[0]}, ${key[1]}) == $dist"
assert distance(key[0], key[1]) == dist
}

View file

@ -0,0 +1,9 @@
levenshtein :: Eq a => [a] -> [a] -> Int
levenshtein s1 s2 = last $ foldl transform [0 .. length s1] s2
where
transform ns@(n:ns1) c = scanl calc (n + 1) $ zip3 s1 ns ns1
where
calc z (c1, x, y) = minimum [y + 1, z + 1, x + fromEnum (c1 /= c)]
main :: IO ()
main = print (levenshtein "kitten" "sitting")

View file

@ -0,0 +1,12 @@
levenshtein :: Eq a => [a] -> [a] -> Int
levenshtein s1 [] = length s1
levenshtein [] s2 = length s2
levenshtein s1@(s1Head:s1Tail) s2@(s2Head:s2Tail)
| s1Head == s2Head = levenshtein s1Tail s2Tail
| otherwise = 1 + minimum [score1, score2, score3]
where score1 = levenshtein s1Tail s2Tail
score2 = levenshtein s1 s2Tail
score3 = levenshtein s1Tail s2
main :: IO ()
main = print (levenshtein "kitten" "sitting")

View file

@ -0,0 +1,21 @@
procedure main()
every process(!&input)
end
procedure process(s)
s ? (s1 := tab(upto(' \t')), s2 := (tab(many(' \t')), tab(0))) | fail
write("'",s1,"' -> '",s2,"' = ", levenshtein(s1,s2))
end
procedure levenshtein(s, t)
if (n := *s+1) = 1 then return *t
if (m := *t+1) = 1 then return *s
every !(d := list(n,0)) := list(m, 0)
every i := 1 to max(n,m) do d[i,1] := d[1,i] := i
every d[1(i := 2 to n, s_i := s[iM1 := i-1]), j := 2 to m] :=
min(d[iM1,j], d[i,jM1:=j-1],
d[iM1,jM1] + if s_i == t[jM1] then -1 else 0) + 1
return d[n,m]-1
end

View file

@ -0,0 +1,6 @@
Io 20110905
Io> Range ; "kitten" levenshtein("sitting")
==> 3
Io> "rosettacode" levenshtein("raisethysword")
==> 8
Io>

View file

@ -0,0 +1,14 @@
levenshtein=:4 :0
D=. x +/&i.&>:&# y
for_i.1+i.#x do.
for_j.1+i.#y do.
if. ((<:i){x)=(<:j){y do.
D=.(D {~<<:i,j) (<i,j)} D
else.
min=. 1+<./D{~(i,j) <@:-"1#:1 2 3
D=. min (<i,j)} D
end.
end.
end.
{:{:D
)

View file

@ -0,0 +1,8 @@
levdist =:4 :0
'a b'=. (x;y) /: (#x),(#y)
D=. >: iz =. i.#b
for_j. a do.
D=. <./\&.(-&iz) (>: D) <. (j ~: b) + |.!.j_index D
end.
{:D
)

View file

@ -0,0 +1,4 @@
'kitten' levenshtein 'sitting'
3
'kitten' levdist 'sitting'
3

View file

@ -0,0 +1,4 @@
timespacex '''kitten'' levenshtein ''sitting'''
0.000113 6016
timespacex '''kitten'' levdist ''sitting'''
1.5e_5 4416

View file

@ -0,0 +1,28 @@
public class Levenshtein {
public static int distance(String a, String b) {
a = a.toLowerCase();
b = b.toLowerCase();
// i == 0
int [] costs = new int [b.length() + 1];
for (int j = 0; j < costs.length; j++)
costs[j] = j;
for (int i = 1; i <= a.length(); i++) {
// j == 0; nw = lev(i - 1, j)
costs[0] = i;
int nw = i - 1;
for (int j = 1; j <= b.length(); j++) {
int cj = Math.min(1 + Math.min(costs[j], costs[j - 1]), a.charAt(i - 1) == b.charAt(j - 1) ? nw : nw + 1);
nw = costs[j];
costs[j] = cj;
}
}
return costs[b.length()];
}
public static void main(String [] args) {
String [] data = { "kitten", "sitting", "saturday", "sunday", "rosettacode", "raisethysword" };
for (int i = 0; i < data.length; i += 2)
System.out.println("distance(" + data[i] + ", " + data[i+1] + ") = " + distance(data[i], data[i+1]));
}
}

View file

@ -0,0 +1,46 @@
public class Levenshtein{
public static int levenshtein(String s, String t){
/* if either string is empty, difference is inserting all chars
* from the other
*/
if(s.length() == 0) return t.length();
if(t.length() == 0) return s.length();
/* if first letters are the same, the difference is whatever is
* required to edit the rest of the strings
*/
if(s.charAt(0) == t.charAt(0))
return levenshtein(s.substring(1), t.substring(1));
/* else try:
* changing first letter of s to that of t,
* remove first letter of s, or
* remove first letter of t
*/
int a = levenshtein(s.substring(1), t.substring(1));
int b = levenshtein(s, t.substring(1));
int c = levenshtein(s.substring(1), t);
if(a > b) a = b;
if(a > c) a = c;
//any of which is 1 edit plus editing the rest of the strings
return a + 1;
}
public static void main(String[] args) {
String s1 = "kitten";
String s2 = "sitting";
System.out.println("distance between '" + s1 + "' and '"
+ s2 + "': " + levenshtein(s1, s2));
s1 = "rosettacode";
s2 = "raisethysword";
System.out.println("distance between '" + s1 + "' and '"
+ s2 + "': " + levenshtein(s1, s2));
StringBuilder sb1 = new StringBuilder(s1);
StringBuilder sb2 = new StringBuilder(s2);
System.out.println("distance between '" + sb1.reverse() + "' and '"
+ sb2.reverse() + "': "
+ levenshtein(sb1.reverse().toString(), sb2.reverse().toString()));
}
}

View file

@ -0,0 +1,73 @@
import static java.lang.Math.abs;
import static java.lang.Math.max;
public class Levenshtein {
public static int ld(String a, String b) {
return distance(a, b, -1);
}
public static boolean ld(String a, String b, int max) {
return distance(a, b, max) <= max;
}
private static int distance(String a, String b, int max) {
if (a == b) return 0;
int la = a.length();
int lb = b.length();
if (max >= 0 && abs(la - lb) > max) return max+1;
if (la == 0) return lb;
if (lb == 0) return la;
if (la < lb) {
int tl = la; la = lb; lb = tl;
String ts = a; a = b; b = ts;
}
int[] cost = new int[lb+1];
for (int i=0; i<=lb; i+=1) {
cost[i] = i;
}
for (int i=1; i<=la; i+=1) {
cost[0] = i;
int prv = i-1;
int min = prv;
for (int j=1; j<=lb; j+=1) {
int act = prv + (a.charAt(i-1) == b.charAt(j-1) ? 0 : 1);
cost[j] = min(1+(prv=cost[j]), 1+cost[j-1], act);
if (prv < min) min = prv;
}
if (max >= 0 && min > max) return max+1;
}
if (max >= 0 && cost[lb] > max) return max+1;
return cost[lb];
}
private static int min(int ... a) {
int min = Integer.MAX_VALUE;
for (int i: a) if (i<min) min = i;
return min;
}
public static void main(String[] args) {
System.out.println(
ld("kitten","kitten") + " " + // 0
ld("kitten","sitten") + " " + // 1
ld("kitten","sittes") + " " + // 2
ld("kitten","sityteng") + " " + // 3
ld("kitten","sittYing") + " " + // 4
ld("rosettacode","raisethysword") + " " + // 8
ld("kitten","kittenaaaaaaaaaaaaaaaaa") + " " + // 17
ld("kittenaaaaaaaaaaaaaaaaa","kitten") // 17
);
System.out.println(
ld("kitten","kitten", 3) + " " + // true
ld("kitten","sitten", 3) + " " + // true
ld("kitten","sittes", 3) + " " + // true
ld("kitten","sityteng", 3) + " " + // true
ld("kitten","sittYing", 3) + " " + // false
ld("rosettacode","raisethysword", 3) + " " + // false
ld("kitten","kittenaaaaaaaaaaaaaaaaa", 3) + " " + // false
ld("kittenaaaaaaaaaaaaaaaaa","kitten", 3) // false
);
}
}

View file

@ -0,0 +1,31 @@
function levenshtein(a, b) {
var t = [], u, i, j, m = a.length, n = b.length;
if (!m) { return n; }
if (!n) { return m; }
for (j = 0; j <= n; j++) { t[j] = j; }
for (i = 1; i <= m; i++) {
for (u = [i], j = 1; j <= n; j++) {
u[j] = a[i - 1] === b[j - 1] ? t[j - 1] : Math.min(t[j - 1], t[j], u[j - 1]) + 1;
} t = u;
} return u[n];
}
// tests
[ ['', '', 0],
['yo', '', 2],
['', 'yo', 2],
['yo', 'yo', 0],
['tier', 'tor', 2],
['saturday', 'sunday', 3],
['mist', 'dist', 1],
['tier', 'tor', 2],
['kitten', 'sitting', 3],
['stop', 'tops', 2],
['rosettacode', 'raisethysword', 8],
['mississippi', 'swiss miss', 8]
].forEach(function(v) {
var a = v[0], b = v[1], t = v[2], d = levenshtein(a, b);
if (d !== t) {
console.log('levenstein("' + a + '","' + b + '") was ' + d + ' should be ' + t);
}
});

View file

@ -0,0 +1,143 @@
(() => {
'use strict';
// levenshtein :: String -> String -> Int
const levenshtein = sa => sb => {
const cs = chars(sa);
const go = (ns, c) => {
const calc = z => tpl => {
const [c1, x, y] = Array.from(tpl);
return minimum([
succ(y),
succ(z),
x + (c !== c1 ? 1 : 0)
]);
};
const [n, ns1] = [ns[0], ns.slice(1)];
return scanl(calc)(succ(n))(
zip3(cs)(ns)(ns1)
);
};
return last(
chars(sb).reduce(
go,
enumFromTo(0)(cs.length)
)
);
};
// ----------------------- TEST ------------------------
const main = () => [
["kitten", "sitting"],
["sitting", "kitten"],
["rosettacode", "raisethysword"],
["raisethysword", "rosettacode"]
].map(uncurry(levenshtein));
// ----------------- GENERIC FUNCTIONS -----------------
// Tuple (,) :: a -> b -> (a, b)
const Tuple = a =>
b => ({
type: 'Tuple',
'0': a,
'1': b,
length: 2
});
// TupleN :: a -> b ... -> (a, b ... )
function TupleN() {
const
args = Array.from(arguments),
n = args.length;
return 2 < n ? Object.assign(
args.reduce((a, x, i) => Object.assign(a, {
[i]: x
}), {
type: 'Tuple' + n.toString(),
length: n
})
) : args.reduce((f, x) => f(x), Tuple);
};
// chars :: String -> [Char]
const chars = s =>
s.split('');
// enumFromTo :: Int -> Int -> [Int]
const enumFromTo = m =>
n => Array.from({
length: 1 + n - m
}, (_, i) => m + i);
// last :: [a] -> a
const last = xs => (
// The last item of a list.
ys => 0 < ys.length ? (
ys.slice(-1)[0]
) : undefined
)(xs);
// minimum :: Ord a => [a] -> a
const minimum = xs => (
// The least value of xs.
ys => 0 < ys.length ? (
ys.slice(1)
.reduce((a, y) => y < a ? y : a, ys[0])
) : undefined
)(xs);
// length :: [a] -> Int
const length = xs =>
// Returns Infinity over objects without finite
// length. This enables zip and zipWith to choose
// the shorter argument when one is non-finite,
// like cycle, repeat etc
'GeneratorFunction' !== xs.constructor.constructor.name ? (
xs.length
) : Infinity;
// scanl :: (b -> a -> b) -> b -> [a] -> [b]
const scanl = f => startValue => xs =>
xs.reduce((a, x) => {
const v = f(a[0])(x);
return Tuple(v)(a[1].concat(v));
}, Tuple(startValue)([startValue]))[1];
// succ :: Enum a => a -> a
const succ = x =>
1 + x;
// uncurry :: (a -> b -> c) -> ((a, b) -> c)
const uncurry = f =>
// A function over a pair, derived
// from a curried function.
function () {
const
args = arguments,
xy = Boolean(args.length % 2) ? (
args[0]
) : args;
return f(xy[0])(xy[1]);
};
// zip3 :: [a] -> [b] -> [c] -> [(a, b, c)]
const zip3 = xs =>
ys => zs => xs
.slice(0, Math.min(...[xs, ys, zs].map(length)))
.map((x, i) => TupleN(x, ys[i], zs[i]));
// MAIN ---
return JSON.stringify(main())
})();

View file

@ -0,0 +1,51 @@
# lookup the distance between s and t in the nested cache,
# which uses basic properties of the Levenshtein distance to save space:
def lookup(s;t):
if (s == t) then 0
elif (s|length) == 0 then (t|length)
elif (t|length) == 0 then (s|length)
elif (s|length) > (t|length) then
.[t] as $t | if $t then $t[s] else null end
else .[s] as $s | if $s then $s[t] else null end
end ;
# output is the updated cache;
# basic properties of the Levenshtein distance are used to save space:
def store(s;t;value):
if (s == t) then .
else (s|length) as $s | (t|length) as $t
| if $s == 0 or $t == 0 then .
elif $s < $t then .[s][t] = value
elif $t < $s then .[t][s] = value
else (.[s][t] = value) | (.[t][s] = value)
end
end ;
# Input is a cache of nested objects; output is [distance, cache]
def ld(s1; s2):
# emit [distance, cache]
# input: cache
def cached_ld(s;t):
lookup(s;t) as $check
| if $check then [ $check, . ]
else ld(s;t)
end
;
# If either string is empty,
# then distance is insertion of the other's characters.
if (s1|length) == 0 then [(s2|length), .]
elif (s2|length) == 0 then [(s1|length), .]
elif (s1[0:1] == s2[0:1]) then
cached_ld(s1[1:]; s2[1:])
else
cached_ld(s1[1:]; s2) as $a
| ($a[1] | cached_ld(s1; s2[1:])) as $b
| ($b[1] | cached_ld(s1[1:]; s2[1:])) as $c
| [$a[0], $b[0], $c[0]] | (min + 1) as $d
| [$d, ($c[1] | store(s1;s2;$d)) ]
end ;
def levenshteinDistance(s;t):
s as $s | t as $t | {} | ld($s;$t) | .[0];

View file

@ -0,0 +1,8 @@
def demo:
"levenshteinDistance between \(.[0]) and \(.[1]) is \( levenshteinDistance(.[0]; .[1]) )";
(["kitten", "sitting"] | demo),
(["rosettacode","raisethysword"] | demo),
(["edocattesor", "drowsyhtesiar"] | demo),
(["this_algorithm_is_similar_to",
"Damerau-Levenshtein_distance"] | demo)

View file

@ -0,0 +1,45 @@
/* Levenshtein Distance, in Jsish */
function levenshtein(a, b) {
var t = [], u, i, j, m = a.length, n = b.length;
if (!m) { return n; }
if (!n) { return m; }
for (j = 0; j <= n; j++) { t[j] = j; }
for (i = 1; i <= m; i++) {
for (u = [i], j = 1; j <= n; j++) {
u[j] = a[i - 1] === b[j - 1] ? t[j - 1] : Math.min(t[j - 1], t[j], u[j - 1]) + 1;
} t = u;
} return u[n];
}
provide('levenshtein', 1);
;levenshtein('', '');
;levenshtein('yo', '');
;levenshtein('', 'yo');
;levenshtein('yo', 'yo');
;levenshtein('tier', 'tor');
;levenshtein('saturday', 'sunday');
;levenshtein('mist', 'dist');
;levenshtein('tier', 'tor');
;levenshtein('kitten', 'sitting');
;levenshtein('stop', 'tops');
;levenshtein('rosettacode', 'raisethysword');
;levenshtein('mississippi', 'swiss miss');
/*
=!EXPECTSTART!=
levenshtein('', '') ==> 0
levenshtein('yo', '') ==> 2
levenshtein('', 'yo') ==> 2
levenshtein('yo', 'yo') ==> 0
levenshtein('tier', 'tor') ==> 2
levenshtein('saturday', 'sunday') ==> 3
levenshtein('mist', 'dist') ==> 1
levenshtein('tier', 'tor') ==> 2
levenshtein('kitten', 'sitting') ==> 3
levenshtein('stop', 'tops') ==> 2
levenshtein('rosettacode', 'raisethysword') ==> 8
levenshtein('mississippi', 'swiss miss') ==> 8
=!EXPECTEND!=
*/

View file

@ -0,0 +1,12 @@
function levendist(s::AbstractString, t::AbstractString)
ls, lt = length.((s, t))
ls == 0 && return lt
lt == 0 && return ls
s₁, t₁ = s[2:end], t[2:end]
ld₁ = levendist(s₁, t₁)
s[1] == t[1] ? ld₁ : 1 + min(ld₁, levendist(s, t₁), levendist(s₁, t))
end
@show levendist("kitten", "sitting") # 3
@show levendist("rosettacode", "raisethysword") # 8

View file

@ -0,0 +1,21 @@
function levendist1(s::AbstractString, t::AbstractString)
ls, lt = length(s), length(t)
if ls > lt
s, t = t, s
ls, lt = lt, ls
end
dist = collect(0:ls)
for (ind2, chr2) in enumerate(t)
newdist = Vector{Int}(ls+1)
newdist[1] = ind2
for (ind1, chr1) in enumerate(s)
if chr1 == chr2
newdist[ind1+1] = dist[ind1]
else
newdist[ind1+1] = 1 + min(dist[ind1], dist[ind1+1], newdist[end])
end
end
dist = newdist
end
return dist[end]
end

View file

@ -0,0 +1,13 @@
using BenchmarkTools
println("\n# levendist(kitten, sitting)")
s, t = "kitten", "sitting"
println(" - Recursive:")
@btime levendist(s, t)
println(" - Iterative:")
@btime levendist1(s, t)
println("\n# levendist(rosettacode, raisethysword)")
s, t = "rosettacode", "raisethysword"
println(" - Recursive:")
@btime levendist(s, t)
println(" - Iterative:")
@btime levendist1(s, t)

View file

@ -0,0 +1,33 @@
// version 1.0.6
// Uses the "iterative with two matrix rows" algorithm referred to in the Wikipedia article.
fun levenshtein(s: String, t: String): Int {
// degenerate cases
if (s == t) return 0
if (s == "") return t.length
if (t == "") return s.length
// create two integer arrays of distances and initialize the first one
val v0 = IntArray(t.length + 1) { it } // previous
val v1 = IntArray(t.length + 1) // current
var cost: Int
for (i in 0 until s.length) {
// calculate v1 from v0
v1[0] = i + 1
for (j in 0 until t.length) {
cost = if (s[i] == t[j]) 0 else 1
v1[j + 1] = Math.min(v1[j] + 1, Math.min(v0[j + 1] + 1, v0[j] + cost))
}
// copy v1 to v0 for next iteration
for (j in 0 .. t.length) v0[j] = v1[j]
}
return v1[t.length]
}
fun main(args: Array<String>) {
println("'kitten' to 'sitting' => ${levenshtein("kitten", "sitting")}")
println("'rosettacode' to 'raisethysword' => ${levenshtein("rosettacode", "raisethysword")}")
println("'sleep' to 'fleeting' => ${levenshtein("sleep", "fleeting")}")
}

View file

@ -0,0 +1,19 @@
fun levenshtein(s: String, t: String,
charScore : (Char, Char) -> Int = { c1, c2 -> if (c1 == c2) 0 else 1}) : Int {
// Special cases
if (s == t) return 0
if (s == "") return t.length
if (t == "") return s.length
val initialRow : List<Int> = (0 until t.length + 1).map { it }.toList()
return (0 until s.length).fold(initialRow, { previous, u ->
(0 until t.length).fold( mutableListOf(u+1), {
row, v -> row.add(minOf(row.last() + 1,
previous[v+1] + 1,
previous[v] + charScore(s[u],t[v])))
row
})
}).last()
}

View file

@ -0,0 +1,13 @@
(defun levenshtein-simple
(('() str)
(length str))
((str '())
(length str))
(((cons a str1) (cons b str2)) (when (== a b))
(levenshtein-simple str1 str2))
(((= (cons _ str1-tail) str1) (= (cons _ str2-tail) str2))
(+ 1 (lists:min
(list
(levenshtein-simple str1 str2-tail)
(levenshtein-simple str1-tail str2)
(levenshtein-simple str1-tail str2-tail))))))

View file

@ -0,0 +1,8 @@
> (levenshtein-simple "a" "a")
0
> (levenshtein-simple "a" "")
1
> (levenshtein-simple "" "a")
1
> (levenshtein-simple "kitten" "sitting")
3

View file

@ -0,0 +1,26 @@
(defun levenshtein-distance (str1 str2)
(let (((tuple distance _) (levenshtein-distance
str1 str2 (dict:new))))
distance))
(defun levenshtein-distance
(((= '() str1) str2 cache)
(tuple (length str2)
(dict:store (tuple str1 str2)
(length str2)
cache)))
((str1 (= '() str2) cache)
(tuple (length str1)
(dict:store (tuple str1 str2)
(length str1)
cache)))
(((cons a str1) (cons b str2) cache) (when (== a b))
(levenshtein-distance str1 str2 cache))
(((= (cons _ str1-tail) str1) (= (cons _ str2-tail) str2) cache)
(case (dict:is_key (tuple str1 str2) cache)
('true (tuple (dict:fetch (tuple str1 str2) cache) cache))
('false (let* (((tuple l1 c1) (levenshtein-distance str1 str2-tail cache))
((tuple l2 c2) (levenshtein-distance str1-tail str2 c1))
((tuple l3 c3) (levenshtein-distance str1-tail str2-tail c2))
(len (+ 1 (lists:min (list l1 l2 l3)))))
(tuple len (dict:store (tuple str1 str2) len c3)))))))

View file

@ -0,0 +1,10 @@
> (levenshtein-distance "a" "a")
0
> (levenshtein-distance "a" "")
1
> (levenshtein-distance "" "a")
1
> (levenshtein-distance "kitten" "sitting")
3
> (levenshtein-distance "rosettacode" "raisethysword")
8

View file

@ -0,0 +1,46 @@
'Levenshtein Distance translated by Brandon Parker
'08/19/10
'from http://www.merriampark.com/ld.htm#VB
'No credit was given to the Visual Basic Author on the site :-(
Print LevenshteinDistance("kitten", "sitting")
End
'Get the minum of three values
Function Minimum(a, b, c)
Minimum = Min(a, Min(b, c))
End Function
'Compute the Levenshtein Distance
Function LevenshteinDistance(string1$, string2$)
n = Len(string1$)
m = Len(string2$)
If n = 0 Then
LevenshteinDistance = m
Exit Function
End If
If m = 0 Then
LevenshteinDistance = n
Exit Function
End If
Dim d(n, m)
For i = 0 To n
d(i, 0) = i
Next i
For i = 0 To m
d(0, i) = i
Next i
For i = 1 To n
si$ = Mid$(string1$, i, 1)
For ii = 1 To m
tj$ = Mid$(string2$, ii, 1)
If si$ = tj$ Then
cost = 0
Else
cost = 1
End If
d(i, ii) = Minimum((d(i - 1, ii) + 1), (d(i, ii - 1) + 1), (d(i - 1, ii - 1) + cost))
Next ii
Next i
LevenshteinDistance = d(n, m)
End Function

View file

@ -0,0 +1,47 @@
implement Levenshtein;
include "sys.m"; sys: Sys;
print: import sys;
include "draw.m";
Levenshtein: module {
init: fn(nil: ref Draw->Context, args: list of string);
# Export distance so that this module can be used as either a
# standalone program or as a library:
distance: fn(s, t: string): int;
};
init(nil: ref Draw->Context, args: list of string)
{
sys = load Sys Sys->PATH;
if(!(len args % 2)) {
sys->fprint(sys->fildes(2), "Provide an even number of arguments!\n");
raise "fail:usage";
}
args = tl args;
while(args != nil) {
(s, t) := (hd args, hd tl args);
args = tl tl args;
print("%s <-> %s => %d\n", s, t, distance(s, t));
}
}
distance(s, t: string): int
{
if(s == "")
return len t;
if(t == "")
return len s;
if(s[0] == t[0])
return distance(s[1:], t[1:]);
a := distance(s[1:], t);
b := distance(s, t[1:]);
c := distance(s[1:], t[1:]);
if(a > b)
a = b;
if(a > c)
a = c;
return a + 1;
}

View file

@ -0,0 +1,23 @@
//Code By Neurox66
function Levenshtein pString1 pString2
put 0 into tPosChar1
repeat for each char tChar1 in pString1
add 1 to tPosChar1
put tPosChar1 into tDistance[tPosChar1][0]
put 0 into tPosChar2
repeat for each char tChar2 in pString2
add 1 to tPosChar2
put tPosChar2 into tDistance[0][tPosChar2]
put 1 into tCost
if tChar1 = tChar2 then
put 0 into tCost
end if
put min((tDistance[tPosChar1-1][tPosChar2] + 1),(tDistance[tPosChar1][tPosChar2-1] + 1),(tDistance[tPosChar1-1][tPosChar2-1] + tCost)) into tDistance[tPosChar1][tPosChar2]
end repeat
end repeat
return tDistance[tPosChar1][tPosChar2]
end Levenshtein
put Levenshtein("kitten","sitting")
put Levenshtein("rosettacode","raisethysword")

View file

@ -0,0 +1,36 @@
def levenshtein(s: string, t: string) -> int:
def makeNxM(n: int, m: int, v: int) -> [[int]]:
let d:[[int]] = vector_reserve(typeof return, n)
for(n) i:
push(d, vector_reserve(typeof return, m))
for(m) j:
push(d[i], v)
return d
let ls = s.length
let lt = t.length
let d = makeNxM(ls + 1, lt + 1, -1)
def dist (i: int, j: int) -> int:
if d[i][j] >= 0:
return d[i][j]
var x = 0
if i == ls:
x = lt - j
else: if j == lt:
x = ls - i
else: if s[i] == t[j]:
x = dist(i + 1, j + 1)
else:
x = dist(i + 1, j + 1)
x = min(x, dist(i, j + 1))
x = min(x, dist(i + 1, j))
x += 1
d[i][j] = x
return x
return dist(0,0)
assert 3 == levenshtein("kitten", "sitting")
assert 8 == levenshtein("rosettacode", "raisethysword")

View file

@ -0,0 +1,20 @@
function leven(s,t)
if s == '' then return t:len() end
if t == '' then return s:len() end
local s1 = s:sub(2, -1)
local t1 = t:sub(2, -1)
if s:sub(0, 1) == t:sub(0, 1) then
return leven(s1, t1)
end
return 1 + math.min(
leven(s1, t1),
leven(s, t1),
leven(s1, t )
)
end
print(leven("kitten", "sitting"))
print(leven("rosettacode", "raisethysword"))

View file

@ -0,0 +1,66 @@
Module Checkit {
\\ Iterative with two matrix rows
function LevenshteinDistance(s$,t$) {
if len(s$)<len(t$) then swap s$, t$
n=len(t$)
m=len(s$)
dim base 0, v0(n+1), v1(n+1)
Rem dim sw() ' we can use stack of values to make the swap.
for i=0 to n : v0(i)=i:next
for i=0 to m-1
v1(0)=i+1
for j=0 to n-1
deletioncost=v0(j+1)+1
insertioncost=v1(j)+1
if mid$(s$,i+1,1)=mid$(t$,j+1,1) then
substitutionCost=v0(j)
else
substitutionCost=v0(j)+1
end if
v1(j+1)=min.data(deletionCost, insertionCost, substitutionCost)
next
Rem sw()=v0():v0()=v1():v1()=sw()
\\ when we push arrays, we only push a pointer to
\\ when we read array (identifier with parenthesis) then we get a copy
\\ between Push and Read any change on arrays included in copies
Push v0(),v1(): Read v0(),v1()
next
=v0(n)
}
Print LevenshteinDistance("kitten","sitting")=3 ' true
Print LevenshteinDistance("Sunday","Saturday")=3 ' true
Print LevenshteinDistance("rosettacode","raisethysword")=8 ' true
}
Checkit
Module Checkit2 {
\\ Iterative with two matrix rows, using pointers to arrays
function LevenshteinDistance(s$,t$) {
if len(s$)<len(t$) then swap s$, t$
n=len(t$)
m=len(s$)
dim base 0, v0(n+1), v1(n+1)
v0=v0() ' v0 is pointer to v0()
v1=v1() ' v1 is pointer to v1()
for i=0 to n : v0(i)=i:next
for i=0 to m-1
return v1, 0:=i+1
for j=0 to n-1
deletioncost=Array(v0,j+1)+1
insertioncost=Array(v1,j)+1
if mid$(s$,i+1,1)=mid$(t$,j+1,1) then
substitutionCost=Array(v0,j)
else
substitutionCost=Array(v0,j)+1
end if
return v1, j+1:=min.data(deletionCost, insertionCost, substitutionCost)
next
swap v0, v1 ' just swap pointers
next
=Array(v0,n)
}
Print LevenshteinDistance("kitten","sitting")=3
Print LevenshteinDistance("Sunday","Saturday")=3
Print LevenshteinDistance("rosettacode","raisethysword")=8
}
Checkit2

View file

@ -0,0 +1,30 @@
function score = levenshtein(s1, s2)
% score = levenshtein(s1, s2)
%
% Calculates the area under the ROC for a given set
% of posterior predictions and labels. Currently limited to two classes.
%
% s1: string
% s2: string
% score: levenshtein distance
%
% Author: Ben Hamner (ben@benhamner.com)
if length(s1) < length(s2)
score = levenshtein(s2, s1);
elseif isempty(s2)
score = length(s1);
else
previous_row = 0:length(s2);
for i=1:length(s1)
current_row = 0*previous_row;
current_row(1) = i;
for j=1:length(s2)
insertions = previous_row(j+1) + 1;
deletions = current_row(j) + 1;
substitutions = previous_row(j) + (s1(i) ~= s2(j));
current_row(j+1) = min([insertions, deletions, substitutions]);
end
previous_row = current_row;
end
score = current_row(end);
end

View file

@ -0,0 +1,6 @@
> with(StringTools):
> Levenshtein("kitten","sitting");
3
> Levenshtein("rosettacode","raisethysword");
8

View file

@ -0,0 +1,2 @@
EditDistance["kitten","sitting"]
EditDistance["rosettacode","raisethysword"]

View file

@ -0,0 +1,2 @@
import "stringUtil"
print "kitten".editDistance("sitting")

View file

@ -0,0 +1,40 @@
string.editDistance = function(s2)
n = self.len
m = s2.len
if n == 0 then return m
if m == 0 then return n
s1chars = self.split("")
s2chars = s2.split("")
d = range(0, m)
lastCost = 0
for i in range(1, n)
s1char = s1chars[i-1]
lastCost = i
jMinus1 = 0
for j in range(1, m)
if s1char == s2chars[jMinus1] then cost = 0 else cost = 1
// set nextCost to the minimum of the following three possibilities:
a = d[j] + 1
b = lastCost + 1
c = cost + d[jMinus1]
if a < b then
if c < a then nextCost = c else nextCost = a
else
if c < b then nextCost = c else nextCost = b
end if
d[jMinus1] = lastCost
lastCost = nextCost
jMinus1 = j
end for
d[m] = lastCost
end for
return nextCost
end function
print "kitten".editDistance("sitting")

View file

@ -0,0 +1,53 @@
MODULE LevenshteinDistance;
FROM InOut IMPORT WriteString, WriteCard, WriteLn;
FROM Strings IMPORT Length;
PROCEDURE levenshtein(s, t: ARRAY OF CHAR): CARDINAL;
CONST MaxLen = 15;
VAR d: ARRAY [0..MaxLen],[0..MaxLen] OF CARDINAL;
lenS, lenT, i, j: CARDINAL;
PROCEDURE min(a, b: CARDINAL): CARDINAL;
BEGIN
IF a<b THEN RETURN a;
ELSE RETURN b;
END;
END min;
BEGIN
lenS := Length(s);
lenT := Length(t);
IF lenS = 0 THEN RETURN lenT;
ELSIF lenT = 0 THEN RETURN lenS;
ELSE
FOR i := 0 TO lenS DO d[i,0] := i; END;
FOR j := 0 TO lenT DO d[0,j] := j; END;
FOR i := 1 TO lenS DO
FOR j := 1 TO lenT DO
IF s[i-1] = t[j-1] THEN
d[i,j] := d[i-1,j-1];
ELSE
d[i,j] :=
min(d[i-1,j] + 1,
min(d[i,j-1] + 1, d[i-1,j-1]+1));
END;
END;
END;
RETURN d[lenS,lenT];
END;
END levenshtein;
PROCEDURE ShowDistance(s, t: ARRAY OF CHAR);
BEGIN
WriteString(s);
WriteString(" -> ");
WriteString(t);
WriteString(": ");
WriteCard(levenshtein(s, t), 0);
WriteLn();
END ShowDistance;
BEGIN
ShowDistance("kitten", "sitting");
ShowDistance("rosettacode", "raisethysword");
END LevenshteinDistance.

View file

@ -0,0 +1,52 @@
/* NetRexx */
options replace format comments java crossref symbols nobinary
n = 0
w = ''
n = n + 1; w[0] = n; w[n] = "kitten sitting"
n = n + 1; w[0] = n; w[n] = "rosettacode raisethysword"
loop n = 1 to w[0]
say w[n].word(1) "->" w[n].word(2)":" levenshteinDistance(w[n].word(1), w[n].word(2))
end n
return
method levenshteinDistance(s, t) private static
s = s.lower
t = t.lower
m = s.length
n = t.length
-- for all i and j, d[i,j] will hold the Levenshtein distance between
-- the first i characters of s and the first j characters of t;
-- note that d has (m+1)x(n+1) values
d = 0
-- source prefixes can be transformed into empty string by
-- dropping all characters (Note, ooRexx arrays are 1-based)
loop i = 2 to m + 1
d[i, 1] = 1
end i
-- target prefixes can be reached from empty source prefix
-- by inserting every characters
loop j = 2 to n + 1
d[1, j] = 1
end j
loop j = 2 to n + 1
loop i = 2 to m + 1
if s.substr(i - 1, 1) == t.substr(j - 1, 1) then do
d[i, j] = d[i - 1, j - 1] -- no operation required
end
else do
d[i, j] = -
(d[i - 1, j] + 1).min( - -- a deletion
(d[i, j - 1] + 1)).min( - -- an insertion
(d[i - 1, j - 1] + 1)) -- a substitution
end
end i
end j
return d[m + 1, n + 1]

View file

@ -0,0 +1,4 @@
import std/editdistance
echo editDistanceAscii("kitten", "sitting")
echo editDistanceAscii("rosettacode", "raisethysword")

View file

@ -0,0 +1,25 @@
import sequtils
func min(a, b, c: int): int {.inline.} = min(a, min(b, c))
proc levenshteinDistance(s1, s2: string): int =
var (s1, s2) = (s1, s2)
if s1.len > s2.len:
swap s1, s2
var distances = toSeq(0..s1.len)
for i2, c2 in s2:
var newDistances = @[i2+1]
for i1, c1 in s1:
if c1 == c2:
newDistances.add(distances[i1])
else:
newDistances.add(1 + min(distances[i1], distances[i1+1], newDistances[newDistances.high]))
distances = newDistances
result = distances[distances.high]
echo levenshteinDistance("kitten","sitting")
echo levenshteinDistance("rosettacode","raisethysword")

Some files were not shown because too many files have changed in this diff Show more