I'm using a tutorial from Rosetta Code to calculate Levenshtein distance. It seems their code is in Swift2 so I get this error Binary operator '+' cannot be applied to operands of type '[Int]' and 'Repeated<String.CharacterView>'
when doing this: var cur = [i + 2] + empty
where let empty = repeatElement(s, count: 0)
. How can I go about this?
Asked
Active
Viewed 2,228 times
4

Jerry U
- 618
- 9
- 22
-
1Not a direct answer to your question, but here http://stackoverflow.com/questions/26990394/slow-swift-arrays-and-strings-performance is an implementation which should require only minor modifications for Swift 3. – Martin R May 21 '17 at 22:06
-
Thanks, worked but would still love to use their(Rosetta) method since it seems shorter. – Jerry U May 21 '17 at 22:25
4 Answers
9
There were a couple of changes to make.
- The construction of the Array empty.
- enumerate() is now enumerated()
- successor() doesn't exist anymore so I replaced it with +1
So the function is now
Swift 4:
func levDis(_ w1: String, _ w2: String) -> Int {
let empty = [Int](repeating:0, count: w2.count)
var last = [Int](0...w2.count)
for (i, char1) in w1.enumerated() {
var cur = [i + 1] + empty
for (j, char2) in w2.enumerated() {
cur[j + 1] = char1 == char2 ? last[j] : min(last[j], last[j + 1], cur[j]) + 1
}
last = cur
}
return last.last!
}
Swift 3:
func levDis(w1: String, w2: String) -> Int {
let (t, s) = (w1.characters, w2.characters)
let empty = Array<Int>(repeating:0, count: s.count)
var last = [Int](0...s.count)
for (i, tLett) in t.enumerated() {
var cur = [i + 1] + empty
for (j, sLett) in s.enumerated() {
cur[j + 1] = tLett == sLett ? last[j] : min(last[j], last[j + 1], cur[j])+1
}
last = cur
}
return last.last!
}

hashier
- 4,670
- 1
- 28
- 41

adamfowlerphoto
- 2,708
- 1
- 11
- 24
3
Updated and improved answer to Swift 4, based on @Spads answer.
extension String {
func levenshteinDistanceScore(to string: String, ignoreCase: Bool = true, trimWhiteSpacesAndNewLines: Bool = true) -> Float {
var firstString = self
var secondString = string
if ignoreCase {
firstString = firstString.lowercased()
secondString = secondString.lowercased()
}
if trimWhiteSpacesAndNewLines {
firstString = firstString.trimmingCharacters(in: .whitespacesAndNewlines)
secondString = secondString.trimmingCharacters(in: .whitespacesAndNewlines)
}
let empty = [Int](repeating:0, count: secondString.count)
var last = [Int](0...secondString.count)
for (i, tLett) in firstString.enumerated() {
var cur = [i + 1] + empty
for (j, sLett) in secondString.enumerated() {
cur[j + 1] = tLett == sLett ? last[j] : Swift.min(last[j], last[j + 1], cur[j])+1
}
last = cur
}
// maximum string length between the two
let lowestScore = max(firstString.count, secondString.count)
if let validDistance = last.last {
return 1 - (Float(validDistance) / Float(lowestScore))
}
return 0.0
}
}
infix operator =~
func =~(string: String, otherString: String) -> Bool {
return string.levenshteinDistanceScore(to: otherString) >= 0.85
}

Daniel Illescas
- 5,346
- 3
- 17
- 23
-
1What does this actually calculate? As far as I know the Levenshtein Distance is an Int, not a float. – hashier Dec 02 '18 at 08:20
-
-
IDK if this still works, but baasically this should return a value between 0 a and 1, 0 being the strings are totally different and 1 the strings are the same; it returns how similar two strings are. – Daniel Illescas Mar 12 '21 at 15:47
2
Since @Daniel Illescas answer is not working, here is working version with Int
return type and with assert.
extension String {
func levenshteinDistance(to string: String, ignoreCase: Bool = true, trimWhiteSpacesAndNewLines: Bool = true) -> Int {
var firstString = self
var secondString = string
if ignoreCase {
firstString = firstString.lowercased()
secondString = secondString.lowercased()
}
if trimWhiteSpacesAndNewLines {
firstString = firstString.trimmingCharacters(in: .whitespacesAndNewlines)
secondString = secondString.trimmingCharacters(in: .whitespacesAndNewlines)
}
let empty = [Int](repeating: 0, count: secondString.count)
var last = [Int](0...secondString.count)
for (i, tLett) in firstString.enumerated() {
var cur = [i + 1] + empty
for (j, sLett) in secondString.enumerated() {
cur[j + 1] = tLett == sLett ? last[j] : Swift.min(last[j], last[j + 1], cur[j]) + 1
}
last = cur
}
if let validDistance = last.last {
return validDistance
}
assertionFailure()
return 0
}
}

Denis Kakačka
- 697
- 1
- 8
- 21
1
func ~=(string: String, otherString: String) -> Bool {
return string.levenshteinDistanceScore(to: otherString) >= 0.85
}

Tiago Martins Peres
- 14,289
- 18
- 86
- 145

akash soni
- 11
- 4
-
This is the correct operator Overloading for levenshteinDistanceScore String Extension. https://stackoverflow.com/a/48976605/9991497 – akash soni Nov 16 '18 at 08:13