12
12
/// - returns: the minimum number of element insertions, removals, or (if
13
13
/// `allowReplacements` is `true`) replacements needed to transform one of
14
14
/// the given sequences into the other. If zero, the sequences are identical.
15
- func editDistance< T: Equatable > ( from fa : [ T ] , to ta : [ T ] , allowReplacements : Bool = true , maxEditDistance : Int = 0 ) -> Int {
15
+ func editDistance( from fa : Substring , to ta : Substring , allowReplacements : Bool = true , maxEditDistance : Int = 0 ) -> Int {
16
+ guard !fa. isEmpty else {
17
+ return ta. count
18
+ }
19
+
20
+ guard !ta. isEmpty else {
21
+ return fa. count
22
+ }
23
+
16
24
// The algorithm implemented below is the "classic"
17
25
// dynamic-programming algorithm for computing the Levenshtein
18
26
// distance, which is described here:
@@ -25,38 +33,21 @@ func editDistance<T: Equatable>(from fa : [T], to ta : [T], allowReplacements :
25
33
// only the entries to the left, top, and top-left are needed. The left
26
34
// entry is in `row[x-1]`, the top entry is what's in `row[x]` from the last
27
35
// iteration, and the top-left entry is stored in Previous.
28
- let m = fa. count
29
- let n = ta. count
30
-
31
- var row = [ Int] ( 1 ... ( n+ 1 ) )
36
+ var pre = [ Int] ( 0 ..< ( ta. count + 1 ) )
37
+ var cur = [ Int] ( repeating: 0 , count: ta. count + 1 )
32
38
33
- for y in 1 ... m {
34
- row [ 0 ] = y
35
- var bestThisRow = row [ 0 ]
36
-
37
- var previous = y - 1
38
- for x in 1 ... n {
39
- let oldRow = row [ x]
40
- if allowReplacements {
41
- row [ x] = min (
42
- previous + ( fa [ y - 1 ] == ta [ x - 1 ] ? 0 : 1 ) ,
43
- min ( row [ x - 1 ] , row [ x] ) + 1
44
- )
45
- } else {
46
- if fa [ y- 1 ] == ta [ x- 1 ] {
47
- row [ x] = previous
48
- } else {
49
- row [ x] = min ( row [ x- 1 ] , row [ x] ) + 1
50
- }
51
- }
52
- previous = oldRow
53
- bestThisRow = min ( bestThisRow, row [ x] )
54
- }
55
-
56
- if maxEditDistance != 0 && bestThisRow > maxEditDistance {
57
- return maxEditDistance + 1
39
+ for (i, ca) in fa. enumerated ( ) {
40
+ cur [ 0 ] = i + 1 ;
41
+ for (j, cb) in ta. enumerated ( ) {
42
+ cur [ j + 1 ] = min (
43
+ // deletion
44
+ pre [ j + 1 ] + 1 , min (
45
+ // insertion
46
+ cur [ j] + 1 ,
47
+ // match or substitution
48
+ pre [ j] + ( ca == cb ? 0 : 1 ) ) )
58
49
}
50
+ swap ( & cur, & pre)
59
51
}
60
-
61
- return row [ n]
52
+ return pre [ ta. count]
62
53
}
0 commit comments