【问题标题】:Find unique values in a Swift Array在 Swift 数组中查找唯一值
【发布时间】:2017-05-07 10:52:52
【问题描述】:

我正在构建一个项目,它可以告诉我一段文本中的独特单词。

我有我的原始字符串 scriptTextView 我已将每个单词添加到数组 scriptEachWordInArray

我现在想创建一个名为 scriptUniqueWords 的数组,它只包含在 scriptEachWordInArray

中出现一次(换句话说是唯一的)的单词

因此,我希望我的 scriptUniqueWords 数组等于 = ["Silent","Holy"]。

我不想创建一个没有重复项的数组,而是一个只包含最初出现一次的值的数组。

var scriptTextView = "Silent Night Holy Night"
var scriptEachWordInArray = ["Silent", "night", "Holy", "night"]
var scriptUniqueWords = [String]()

for i in 0..<scriptEachWordInArray.count {

    if scriptTextView.components(separatedBy: "\(scriptEachWordInArray[i]) ").count == 1 {
        scriptUniqueWords.append(scriptEachWordInArray[i])
        print("Unique word \(scriptEachWordInArray[i])")}

}

【问题讨论】:

  • 试过Set ?
  • @jtbandes @Bek 谢谢,但Set 技术不会删除所有重复项,因此每个单词将出现一次而不是可能出现多次。夜晚只会出现在阵列中一次,而不是两次。而我希望只隔离独特的价值观。我已经尝试过了,或者我错过了什么。
  • 重新打开,因为我确信这个问题与其他链接的问题不同。但是,我仍然认为您可以使用 Sets 来解决问题。
  • @jtbandes 当然,如果你认为我错了,un-dupe-hammering 是完全合理的。

标签: arrays swift unique


【解决方案1】:

斯威夫特

让我们试试吧。

let array = ["1", "1", "2", "2", "3", "3"]
let unique = Array(Set(array))
// ["1", "2", "3"]

【讨论】:

    【解决方案2】:

    您可以过滤数组中已经包含的值:

    let newArray = array.filter { !array.contains($0) }
    

    【讨论】:

    • 这行不通,因为array 已经包含了它自己的所有元素。因此表达式 !array.contains($0) 总是返回 false。
    【解决方案3】:

    过滤掉唯一词而不保留顺序

    作为NSCountedSet 的另一种选择,您可以使用字典来计算每个单词的出现次数,并过滤掉只出现一次的单词:

    let scriptEachWordInArray = ["Silent", "night", "Holy", "night"]
    
    var freqs: [String: Int] = [:]
    scriptEachWordInArray.forEach { freqs[$0] = (freqs[$0] ?? 0) + 1 }
    
    let scriptUniqueWords = freqs.flatMap { $0.1 == 1 ? $0.0 : nil }
    print(scriptUniqueWords) // ["Holy", "Silent"]
    

    但是,此解决方案(以及使用 NSCountedSet 的解决方案)不会保留原始数组的顺序,因为字典和 NSCountedSet 都是无序集合。


    在保留顺序的同时过滤掉唯一的单词

    如果您想保留原始数组的顺序(删除多次出现的元素),您可以计算每个单词的频率,但将其存储在 (String, Int) 元组数组而不是字典中。

    使用Collection extension from this Q&A

    extension Collection where Iterator.Element: Hashable {
        var frequencies: [(Iterator.Element, Int)] {
            var seen: [Iterator.Element: Int] = [:]
            var frequencies: [(Iterator.Element, Int)] = []
            forEach {
                if let idx = seen[$0] {
                    frequencies[idx].1 += 1
                }
                else {
                    seen[$0] = frequencies.count
                    frequencies.append(($0, 1))
                }
            }
            return frequencies
        }
    }
    
    // or, briefer but worse at showing intent
    extension Collection where Iterator.Element: Hashable {
        var frequencies: [(Iterator.Element, Int)] {
            var seen: [Iterator.Element: Int] = [:]
            var frequencies: [(Iterator.Element, Int)] = []
            for elem in self {
                seen[elem].map { frequencies[$0].1 += 1 } ?? {
                    seen[elem] = frequencies.count
                    return frequencies.append((elem, 1))
                }()
            }
            return frequencies
        }
    }
    

    ...您可以过滤掉数组的唯一单词(同时保留顺序)

    let scriptUniqueWords = scriptEachWordInArray.frequencies
        .flatMap { $0.1 == 1 ? $0.0 : nil }
    
    print(scriptUniqueWords) // ["Silent", "Holy"]
    

    【讨论】:

    • 为此使用 NSCountedSet。
    • @Alexander NSCountedSet 是一种很好的 Foundation 方法;多样性,恕我直言,对于 SO 答案很有趣(因此上述字典方法的“作为另一种选择”)。当我们想保留原始数组的顺序时,包含一个方法也很有用。
    • @dfri 你可能对此感兴趣stackoverflow.com/a/46376175/2303865
    【解决方案4】:

    您可以使用NSCountedSet

    let text = "Silent Night Holy Night"
    let words = text.lowercased().components(separatedBy: " ")
    let countedSet = NSCountedSet(array: words)
    let singleOccurrencies = countedSet.filter { countedSet.count(for: $0) == 1 }.flatMap { $0 as? String }
    

    现在singleOccurrencies 包含["holy", "silent"]

    【讨论】:

      猜你喜欢
      • 2014-02-09
      • 1970-01-01
      • 2022-11-15
      • 1970-01-01
      • 2015-12-08
      • 1970-01-01
      • 2021-11-08
      • 2020-05-13
      相关资源
      最近更新 更多