使用Swift4,我想根据与给定searchTerm最接近的匹配对字符串数组进行排序。重要的是,如果searchTerm可以找到完全匹配,那么returnArray应该预先显示这个searchTerm!
示例:鉴于Array = ["Hello world", "Hello Jamaica", "Hello", "Family", "Hel"]
和searchTerm = "Hello"
,算法应该返回:
["Hello", "Hello world", "Hello Jamaica", "Hel", "Family"]
。
方法1:我尝试使用FuzzyMatching - 它以某种方式工作(即它确实根据给定的searchTerm对inputArray进行排序,但它没有提前确定匹配!即使用FuzzyMatching我根据子串匹配实现了良好的排序和句法排序。但它没有给我带来returnArray中的完全匹配。
方法2:然后我尝试了自己的算法 - (见下面的代码)。但是如果数组中有几个字符串都以我的searchTerm开头(即将searchTerm作为前缀),那么不知何故我的算法不是很好。
static func bestMatchFilterdStringArray(inputArray: [String], searchTerm: String) -> [String] {
let matchingTerms = inputArray
.filter { $0.range(of: searchTerm, options: .caseInsensitive) != nil }
.sorted { ($0.hasPrefix(searchTerm) ? 0 : 1) < ($1.hasPrefix(searchTerm) ? 0 : 1) }
return matchingTerms
}
如何在Swift4中完成“最近匹配的字符串数组排序”?特别是在returnArray中为我提前精确匹配?任何帮助赞赏!
您可以使用Levenshtein distance得分将您的搜索词与数组中的每个字符串进行比较,得分最高的那个将是结果数组中的第一个词等。您的结果将是按得分的降序排列的字符串数组。
以下扩展到字符串可用于获得Levenshtein距离得分。在这个算法中,值越高,等于越好。
extension String {
func levenshteinDistanceScore(to string: String, ignoreCase: Bool = true, trimWhiteSpacesAndNewLines: Bool = true) -> Double {
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 - (Double(validDistance) / Double(lowestScore))
}
return 0.0
}
}