Swift中最接近的字符串数组排序

时间:2017-12-13 13:53:03

标签: arrays swift sorting match closest

使用Swift4,我想根据与给定searchTerm最接近的匹配对字符串数组进行排序。重要的是,如果searchTerm可以找到完全匹配,那么returnArray应该预先显示这个searchTerm!

示例:给定 Dim vDbld As Variant 'for the date by building ReDim vDbld(1 To 13, 1 To 2) vDbld(1, 1) = "Irving Building" vDbld(2, 1) = "Memorial Building" vDbld(3, 1) = "West Tower" vDbld(4, 1) = "Witting Surgical Center" vDbld(5, 1) = "Madison Irving Surgical Center" vDbld(6, 1) = "Marley Education Center" vDbld(7, 1) = "410 South Crouse" vDbld(8, 1) = "Physicians Office Building" vDbld(9, 1) = "Crouse Business Center" vDbld(10, 1) = "Commonwealth Place" vDbld(11, 1) = "Irving - Memorial Connector" vDbld(12, 1) = "Crouse Garage" vDbld(13, 1) = "CNY Medical Center"

Array = ["Hello world", "Hello Jamaica", "Hello", "Family", "Hel"],算法应返回:

searchTerm = "Hello"

方法1: 我尝试使用FuzzyMatching - 它以某种方式工作(即它确实根据给定的searchTerm对inputArray进行排序,但它没有提前确定匹配!即使用FuzzyMatching我根据子串实现了良好的排序 - 匹配和句法排序。但它并没有在returnArray中为我提供完全匹配。

方法2: 然后我尝试了自己的算法 - (见下面的代码)。但是如果数组中有几个字符串都以我的searchTerm开头(即将searchTerm作为前缀),那么我的算法不太好用。

["Hello", "Hello world", "Hello Jamaica", "Hel", "Family"]

如何在Swift4中完成“最近匹配的字符串数组排序”?特别是在returnArray中为我提前精确匹配?任何帮助赞赏!

1 个答案:

答案 0 :(得分:3)

您可以使用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
    }
}