Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
2
Task/Levenshtein-distance/00-META.yaml
Normal file
2
Task/Levenshtein-distance/00-META.yaml
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
from: http://rosettacode.org/wiki/Levenshtein_distance
|
||||
27
Task/Levenshtein-distance/00-TASK.txt
Normal file
27
Task/Levenshtein-distance/00-TASK.txt
Normal 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:
|
||||
::# '''k'''itten '''s'''itten (substitution of 'k' with 's')
|
||||
::# sitt'''e'''n sitt'''i'''n (substitution of 'e' with 'i')
|
||||
::# sittin sittin'''g''' (insert 'g' at the end).
|
||||
|
||||
<br>
|
||||
''The Levenshtein distance between "'''rosettacode'''", "'''raisethysword'''" is '''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 "kitten" and "sitting".
|
||||
|
||||
|
||||
;Related task:
|
||||
* [[Longest common subsequence]]
|
||||
|
||||
|
||||
{{Template:Strings}}
|
||||
<br><br>
|
||||
|
||||
18
Task/Levenshtein-distance/11l/levenshtein-distance.11l
Normal file
18
Task/Levenshtein-distance/11l/levenshtein-distance.11l
Normal 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’))
|
||||
173
Task/Levenshtein-distance/360-Assembly/levenshtein-distance.360
Normal file
173
Task/Levenshtein-distance/360-Assembly/levenshtein-distance.360
Normal 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
|
||||
50
Task/Levenshtein-distance/ALGOL-68/levenshtein-distance.alg
Normal file
50
Task/Levenshtein-distance/ALGOL-68/levenshtein-distance.alg
Normal 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
|
||||
44
Task/Levenshtein-distance/AWK/levenshtein-distance-1.awk
Normal file
44
Task/Levenshtein-distance/AWK/levenshtein-distance-1.awk
Normal 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.
|
||||
}
|
||||
28
Task/Levenshtein-distance/AWK/levenshtein-distance-2.awk
Normal file
28
Task/Levenshtein-distance/AWK/levenshtein-distance-2.awk
Normal 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]
|
||||
}
|
||||
|
|
@ -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
|
||||
34
Task/Levenshtein-distance/Ada/levenshtein-distance.ada
Normal file
34
Task/Levenshtein-distance/Ada/levenshtein-distance.ada
Normal 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;
|
||||
45
Task/Levenshtein-distance/Aime/levenshtein-distance.aime
Normal file
45
Task/Levenshtein-distance/Aime/levenshtein-distance.aime
Normal 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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1 @@
|
|||
{3, 3, 8, 8}
|
||||
16
Task/Levenshtein-distance/Arc/levenshtein-distance.arc
Normal file
16
Task/Levenshtein-distance/Arc/levenshtein-distance.arc
Normal 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))
|
||||
|
|
@ -0,0 +1 @@
|
|||
print levenshtein "kitten" "sitting"
|
||||
|
|
@ -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)
|
||||
|
|
@ -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)
|
||||
7
Task/Levenshtein-distance/BQN/levenshtein-distance-1.bqn
Normal file
7
Task/Levenshtein-distance/BQN/levenshtein-distance-1.bqn
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
Levenshtein ← {
|
||||
𝕨 𝕊"": ≠𝕨;
|
||||
""𝕊 𝕩: ≠𝕩;
|
||||
𝕨 𝕊 𝕩:
|
||||
Tail←1⊸↓
|
||||
𝕨 =○⊑◶⟨1+·⌊´ 𝕊○Tail ∾ Tail⊸𝕊 ∾ 𝕊⟜Tail, 𝕊○Tail⟩ 𝕩
|
||||
}
|
||||
1
Task/Levenshtein-distance/BQN/levenshtein-distance-2.bqn
Normal file
1
Task/Levenshtein-distance/BQN/levenshtein-distance-2.bqn
Normal file
|
|
@ -0,0 +1 @@
|
|||
Levenshtein ← @⊸∾⊸{¯1⊑(↕≠𝕨)𝕨{(1⊸+⊸⌊`1⊸+⌊⊑⊸»+𝕨≠𝕗˙)𝕩}´⌽𝕩}
|
||||
6
Task/Levenshtein-distance/BQN/levenshtein-distance-3.bqn
Normal file
6
Task/Levenshtein-distance/BQN/levenshtein-distance-3.bqn
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
"kitten" Levenshtein "sitting"
|
||||
3
|
||||
"Saturday" Levenshtein "Sunday"
|
||||
3
|
||||
"rosettacode" Levenshtein "raisethysword"
|
||||
8
|
||||
|
|
@ -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);
|
||||
55
Task/Levenshtein-distance/C++/levenshtein-distance-1.cpp
Normal file
55
Task/Levenshtein-distance/C++/levenshtein-distance-1.cpp
Normal 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;
|
||||
}
|
||||
40
Task/Levenshtein-distance/C++/levenshtein-distance-2.cpp
Normal file
40
Task/Levenshtein-distance/C++/levenshtein-distance-2.cpp
Normal 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;
|
||||
}
|
||||
50
Task/Levenshtein-distance/C-sharp/levenshtein-distance.cs
Normal file
50
Task/Levenshtein-distance/C-sharp/levenshtein-distance.cs
Normal 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>");
|
||||
}
|
||||
}
|
||||
}
|
||||
45
Task/Levenshtein-distance/C/levenshtein-distance-1.c
Normal file
45
Task/Levenshtein-distance/C/levenshtein-distance-1.c
Normal 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;
|
||||
}
|
||||
44
Task/Levenshtein-distance/C/levenshtein-distance-2.c
Normal file
44
Task/Levenshtein-distance/C/levenshtein-distance-2.c
Normal 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;
|
||||
}
|
||||
44
Task/Levenshtein-distance/CLU/levenshtein-distance.clu
Normal file
44
Task/Levenshtein-distance/CLU/levenshtein-distance.clu
Normal 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
|
||||
62
Task/Levenshtein-distance/COBOL/levenshtein-distance.cobol
Normal file
62
Task/Levenshtein-distance/COBOL/levenshtein-distance.cobol
Normal 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)
|
||||
.
|
||||
13
Task/Levenshtein-distance/Clojure/levenshtein-distance-1.clj
Normal file
13
Task/Levenshtein-distance/Clojure/levenshtein-distance-1.clj
Normal 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"))
|
||||
21
Task/Levenshtein-distance/Clojure/levenshtein-distance-2.clj
Normal file
21
Task/Levenshtein-distance/Clojure/levenshtein-distance-2.clj
Normal 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))))))
|
||||
|
|
@ -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")
|
||||
|
|
@ -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"))
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
require "levenshtein"
|
||||
puts Levenshtein.distance("kitten", "sitting")
|
||||
puts Levenshtein.distance("rosettacode", "raisethysword")
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
5
Task/Levenshtein-distance/D/levenshtein-distance-1.d
Normal file
5
Task/Levenshtein-distance/D/levenshtein-distance-1.d
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
void main() {
|
||||
import std.stdio, std.algorithm;
|
||||
|
||||
levenshteinDistance("kitten", "sitting").writeln;
|
||||
}
|
||||
32
Task/Levenshtein-distance/D/levenshtein-distance-2.d
Normal file
32
Task/Levenshtein-distance/D/levenshtein-distance-2.d
Normal 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]));
|
||||
}
|
||||
15
Task/Levenshtein-distance/D/levenshtein-distance-3.d
Normal file
15
Task/Levenshtein-distance/D/levenshtein-distance-3.d
Normal 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;
|
||||
}
|
||||
23
Task/Levenshtein-distance/DWScript/levenshtein-distance.dw
Normal file
23
Task/Levenshtein-distance/DWScript/levenshtein-distance.dw
Normal 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'));
|
||||
63
Task/Levenshtein-distance/Delphi/levenshtein-distance.delphi
Normal file
63
Task/Levenshtein-distance/Delphi/levenshtein-distance.delphi
Normal 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.
|
||||
|
|
@ -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")
|
||||
43
Task/Levenshtein-distance/ERRE/levenshtein-distance.erre
Normal file
43
Task/Levenshtein-distance/ERRE/levenshtein-distance.erre
Normal 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
|
||||
28
Task/Levenshtein-distance/EchoLisp/levenshtein-distance.l
Normal file
28
Task/Levenshtein-distance/EchoLisp/levenshtein-distance.l
Normal 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
|
||||
5
Task/Levenshtein-distance/Ela/levenshtein-distance-1.ela
Normal file
5
Task/Levenshtein-distance/Ela/levenshtein-distance-1.ela
Normal 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)]
|
||||
1
Task/Levenshtein-distance/Ela/levenshtein-distance-2.ela
Normal file
1
Task/Levenshtein-distance/Ela/levenshtein-distance-2.ela
Normal file
|
|
@ -0,0 +1 @@
|
|||
(levenshtein "kitten" "sitting", levenshtein "rosettacode" "raisethysword")
|
||||
28
Task/Levenshtein-distance/Elixir/levenshtein-distance.elixir
Normal file
28
Task/Levenshtein-distance/Elixir/levenshtein-distance.elixir
Normal 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)
|
||||
35
Task/Levenshtein-distance/Erlang/levenshtein-distance-1.erl
Normal file
35
Task/Levenshtein-distance/Erlang/levenshtein-distance-1.erl
Normal 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.
|
||||
|
|
@ -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}
|
||||
|
|
@ -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")
|
||||
32
Task/Levenshtein-distance/F-Sharp/levenshtein-distance-1.fs
Normal file
32
Task/Levenshtein-distance/F-Sharp/levenshtein-distance-1.fs
Normal 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
|
||||
22
Task/Levenshtein-distance/F-Sharp/levenshtein-distance-2.fs
Normal file
22
Task/Levenshtein-distance/F-Sharp/levenshtein-distance-2.fs
Normal 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")
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
USING: lcs prettyprint ;
|
||||
"kitten" "sitting" levenshtein .
|
||||
23
Task/Levenshtein-distance/Forth/levenshtein-distance.fth
Normal file
23
Task/Levenshtein-distance/Forth/levenshtein-distance.fth
Normal 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
|
||||
38
Task/Levenshtein-distance/Fortran/levenshtein-distance.f
Normal file
38
Task/Levenshtein-distance/Fortran/levenshtein-distance.f
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1 @@
|
|||
println[editDistance["kitten","sitting"]]
|
||||
|
|
@ -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
|
||||
38
Task/Levenshtein-distance/Go/levenshtein-distance-1.go
Normal file
38
Task/Levenshtein-distance/Go/levenshtein-distance-1.go
Normal 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)]
|
||||
}
|
||||
24
Task/Levenshtein-distance/Go/levenshtein-distance-2.go
Normal file
24
Task/Levenshtein-distance/Go/levenshtein-distance-2.go
Normal 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))
|
||||
}
|
||||
19
Task/Levenshtein-distance/Groovy/levenshtein-distance.groovy
Normal file
19
Task/Levenshtein-distance/Groovy/levenshtein-distance.groovy
Normal 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
|
||||
}
|
||||
|
|
@ -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")
|
||||
12
Task/Levenshtein-distance/Haskell/levenshtein-distance-2.hs
Normal file
12
Task/Levenshtein-distance/Haskell/levenshtein-distance-2.hs
Normal 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")
|
||||
21
Task/Levenshtein-distance/Icon/levenshtein-distance.icon
Normal file
21
Task/Levenshtein-distance/Icon/levenshtein-distance.icon
Normal 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
|
||||
6
Task/Levenshtein-distance/Io/levenshtein-distance.io
Normal file
6
Task/Levenshtein-distance/Io/levenshtein-distance.io
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
Io 20110905
|
||||
Io> Range ; "kitten" levenshtein("sitting")
|
||||
==> 3
|
||||
Io> "rosettacode" levenshtein("raisethysword")
|
||||
==> 8
|
||||
Io>
|
||||
14
Task/Levenshtein-distance/J/levenshtein-distance-1.j
Normal file
14
Task/Levenshtein-distance/J/levenshtein-distance-1.j
Normal 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
|
||||
)
|
||||
8
Task/Levenshtein-distance/J/levenshtein-distance-2.j
Normal file
8
Task/Levenshtein-distance/J/levenshtein-distance-2.j
Normal 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
|
||||
)
|
||||
4
Task/Levenshtein-distance/J/levenshtein-distance-3.j
Normal file
4
Task/Levenshtein-distance/J/levenshtein-distance-3.j
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
'kitten' levenshtein 'sitting'
|
||||
3
|
||||
'kitten' levdist 'sitting'
|
||||
3
|
||||
4
Task/Levenshtein-distance/J/levenshtein-distance-4.j
Normal file
4
Task/Levenshtein-distance/J/levenshtein-distance-4.j
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
timespacex '''kitten'' levenshtein ''sitting'''
|
||||
0.000113 6016
|
||||
timespacex '''kitten'' levdist ''sitting'''
|
||||
1.5e_5 4416
|
||||
28
Task/Levenshtein-distance/Java/levenshtein-distance-1.java
Normal file
28
Task/Levenshtein-distance/Java/levenshtein-distance-1.java
Normal 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]));
|
||||
}
|
||||
}
|
||||
46
Task/Levenshtein-distance/Java/levenshtein-distance-2.java
Normal file
46
Task/Levenshtein-distance/Java/levenshtein-distance-2.java
Normal 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()));
|
||||
}
|
||||
}
|
||||
73
Task/Levenshtein-distance/Java/levenshtein-distance-3.java
Normal file
73
Task/Levenshtein-distance/Java/levenshtein-distance-3.java
Normal 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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
143
Task/Levenshtein-distance/JavaScript/levenshtein-distance-2.js
Normal file
143
Task/Levenshtein-distance/JavaScript/levenshtein-distance-2.js
Normal 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())
|
||||
})();
|
||||
51
Task/Levenshtein-distance/Jq/levenshtein-distance-1.jq
Normal file
51
Task/Levenshtein-distance/Jq/levenshtein-distance-1.jq
Normal 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];
|
||||
8
Task/Levenshtein-distance/Jq/levenshtein-distance-2.jq
Normal file
8
Task/Levenshtein-distance/Jq/levenshtein-distance-2.jq
Normal 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)
|
||||
45
Task/Levenshtein-distance/Jsish/levenshtein-distance.jsish
Normal file
45
Task/Levenshtein-distance/Jsish/levenshtein-distance.jsish
Normal 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!=
|
||||
*/
|
||||
12
Task/Levenshtein-distance/Julia/levenshtein-distance-1.julia
Normal file
12
Task/Levenshtein-distance/Julia/levenshtein-distance-1.julia
Normal 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
|
||||
21
Task/Levenshtein-distance/Julia/levenshtein-distance-2.julia
Normal file
21
Task/Levenshtein-distance/Julia/levenshtein-distance-2.julia
Normal 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
|
||||
13
Task/Levenshtein-distance/Julia/levenshtein-distance-3.julia
Normal file
13
Task/Levenshtein-distance/Julia/levenshtein-distance-3.julia
Normal 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)
|
||||
|
|
@ -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")}")
|
||||
}
|
||||
|
|
@ -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()
|
||||
|
||||
}
|
||||
13
Task/Levenshtein-distance/LFE/levenshtein-distance-1.lfe
Normal file
13
Task/Levenshtein-distance/LFE/levenshtein-distance-1.lfe
Normal 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))))))
|
||||
8
Task/Levenshtein-distance/LFE/levenshtein-distance-2.lfe
Normal file
8
Task/Levenshtein-distance/LFE/levenshtein-distance-2.lfe
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
> (levenshtein-simple "a" "a")
|
||||
0
|
||||
> (levenshtein-simple "a" "")
|
||||
1
|
||||
> (levenshtein-simple "" "a")
|
||||
1
|
||||
> (levenshtein-simple "kitten" "sitting")
|
||||
3
|
||||
26
Task/Levenshtein-distance/LFE/levenshtein-distance-3.lfe
Normal file
26
Task/Levenshtein-distance/LFE/levenshtein-distance-3.lfe
Normal 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)))))))
|
||||
10
Task/Levenshtein-distance/LFE/levenshtein-distance-4.lfe
Normal file
10
Task/Levenshtein-distance/LFE/levenshtein-distance-4.lfe
Normal 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
|
||||
|
|
@ -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
|
||||
47
Task/Levenshtein-distance/Limbo/levenshtein-distance.limbo
Normal file
47
Task/Levenshtein-distance/Limbo/levenshtein-distance.limbo
Normal 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;
|
||||
}
|
||||
|
|
@ -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")
|
||||
|
|
@ -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")
|
||||
20
Task/Levenshtein-distance/Lua/levenshtein-distance.lua
Normal file
20
Task/Levenshtein-distance/Lua/levenshtein-distance.lua
Normal 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"))
|
||||
|
|
@ -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
|
||||
30
Task/Levenshtein-distance/MATLAB/levenshtein-distance.m
Normal file
30
Task/Levenshtein-distance/MATLAB/levenshtein-distance.m
Normal 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
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
> with(StringTools):
|
||||
> Levenshtein("kitten","sitting");
|
||||
3
|
||||
|
||||
> Levenshtein("rosettacode","raisethysword");
|
||||
8
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
EditDistance["kitten","sitting"]
|
||||
EditDistance["rosettacode","raisethysword"]
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
import "stringUtil"
|
||||
print "kitten".editDistance("sitting")
|
||||
|
|
@ -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")
|
||||
53
Task/Levenshtein-distance/Modula-2/levenshtein-distance.mod2
Normal file
53
Task/Levenshtein-distance/Modula-2/levenshtein-distance.mod2
Normal 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.
|
||||
|
|
@ -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]
|
||||
4
Task/Levenshtein-distance/Nim/levenshtein-distance-1.nim
Normal file
4
Task/Levenshtein-distance/Nim/levenshtein-distance-1.nim
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
import std/editdistance
|
||||
|
||||
echo editDistanceAscii("kitten", "sitting")
|
||||
echo editDistanceAscii("rosettacode", "raisethysword")
|
||||
25
Task/Levenshtein-distance/Nim/levenshtein-distance-2.nim
Normal file
25
Task/Levenshtein-distance/Nim/levenshtein-distance-2.nim
Normal 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
Loading…
Add table
Add a link
Reference in a new issue