【问题标题】:How to sort an array of string by similarity to specific key如何通过与特定键的相似性对字符串数组进行排序
【发布时间】:2018-04-18 06:14:14
【问题描述】:

给出如下:

var theArray: [String] = ["uncool", "chill", "nifty", "precooled", "dandy", "cool"]

我想按照单词与关键字的相似程度对数组进行排序。

var keyWord: String = "cool"

想要的结果是:

print// ["cool", "uncool", "precooled", ...] 然后就不再重要了。但是are key 或contain it 应该是第一个对象。

到目前为止,我最近的一次尝试是:

let _theArray = entries.sorted { element1, element2 in

     return element1.contains(keyWord) && !element2.contains(keyWord)
}

但这会导致uncool 成为第一个项目,然后是precooled,最相关的项目cool 甚至排在nifty 之后。

我错过了什么?

【问题讨论】:

标签: arrays swift string sorting


【解决方案1】:

首先,您需要衡量两个字符串的相似程度。这是一个简单的例子:

extension String {
    func equalityScore(with string: String) -> Double {
        if self == string {
            return 2     // the greatest equality score this method can give
        } else if self.contains(string) {
            return 1 + 1 / Double(self.count - string.count)   // contains our term, so the score will be between 1 and 2, depending on number of letters.
        } else {
            // you could of course have other criteria, like string.contains(self)
            return 1 / Double(abs(self.count - string.count))
        }
    }
}

一旦你有了它,你就可以用它来对数组进行排序:

var theArray: [String] = ["uncool", "chill", "nifty", "precooled", "dandy", "cool"]

var compareString = "cool"

theArray.sort { lhs, rhs in
    return lhs.equalityScore(with: compareString) > rhs.equalityScore(with: compareString)
}

结果:["cool", "uncool", "precooled", "chill", "nifty", "dandy"]

【讨论】:

  • 如果数组是:["chill", "nifty", "precooled", "cooldaddy", "cool", "coolguy", "dandy", "uncool"] 结果不正确: [“cool”, “uncool”, “coolguy”, “precooled”, “cooldaddy”, “chill”, “nifty”, “dandy”]
【解决方案2】:

您可以定义自己的相似度排序方法。请注意,我还添加了一个 hasPrefix 优先级,而不是只包含关键字的那些,如果你不想要它,你可以删除它:

var theArray = ["chill", "nifty", "precooled", "cooldaddy", "cool", "coolguy", "dandy", "uncool"]
let key = "cool"

let sorted = theArray.sorted {
    if $0 == key && $1 != key {
        return true
    }
    else if $0.hasPrefix(key) && !$1.hasPrefix(key)  {
        return true
    }
    else if !$0.hasPrefix(key) && $1.hasPrefix(key)  {
        return false
    }
    else if $0.hasPrefix(key) && $1.hasPrefix(key)
        && $0.count < $1.count  {
        return true
    }
    else if $0.contains(key) && !$1.contains(key) {
        return true
    }
    else if !$0.contains(key) && $1.contains(key) {
        return false
    }
    else if $0.contains(key) && $1.contains(key)
        && $0.count < $1.count {
        return true
    }
    return false
}

print(sorted)   // ["cool", "coolguy", "cooldaddy", "uncool", "precooled", "chill", "nifty", "dandy"]

您还可以扩展 Sequence 并创建一个按键相似度排序的方法:

extension Sequence where Element: StringProtocol {
    func sorted<S>(by key: S) -> [Element] where S: StringProtocol {
        sorted {
            if $0 == key && $1 != key {
                return true
            }
            else if $0.hasPrefix(key) && !$1.hasPrefix(key)  {
                return true
            }
            else if !$0.hasPrefix(key) && $1.hasPrefix(key)  {
                return false
            }
            else if $0.hasPrefix(key) && $1.hasPrefix(key)
                && $0.count < $1.count  {
                return true
            }
            else if $0.contains(key) && !$1.contains(key) {
                return true
            }
            else if !$0.contains(key) && $1.contains(key) {
                return false
            }
            else if $0.contains(key) && $1.contains(key)
                && $0.count < $1.count {
                return true
            }
            return false
        }
    }
}

let sorted = theArray.sorted(by: key)  // "cool", "coolguy", "cooldaddy", "uncool", "precooled", "chill", "nifty", "dandy"]

还有变异版本:

extension MutableCollection where Element: StringProtocol, Self: RandomAccessCollection {
    mutating func sort<S>(by key: S) where S: StringProtocol {
        sort {
            if $0 == key && $1 != key {
                return true
            }
            else if $0.hasPrefix(key) && !$1.hasPrefix(key)  {
                return true
            }
            else if !$0.hasPrefix(key) && $1.hasPrefix(key)  {
                return false
            }
            else if $0.hasPrefix(key) && $1.hasPrefix(key)
                && $0.count < $1.count  {
                return true
            }
            else if $0.contains(key) && !$1.contains(key) {
                return true
            }
            else if !$0.contains(key) && $1.contains(key) {
                return false
            }
            else if $0.contains(key) && $1.contains(key)
                && $0.count < $1.count {
                return true
            }
            return false
        }
    }
}

【讨论】:

  • 通过使用符合 CaseInsensitive 模式匹配条件的 .localizedCaseInsensitiveContains(key)。 :)
  • @Jack 问题是如何进行自定义排序。 OP提供的输入都是小写的,没有提到它。所以你甚至不知道这是否是 OP 需要的。
  • @Jack 不区分大小写(未本地化)示例dropbox.com/s/bhc5fr3x5q4bvgl/…
  • @Jack 不区分大小写(本地化)示例dropbox.com/s/eiml3zpxs45lp9t/…
  • @HassanTaleb 是的,有一个缺失的条件。检查我上次的编辑。
猜你喜欢
  • 2011-11-05
  • 2017-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多