在 Swift 数组中查找唯一值

Find unique values in a Swift Array

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

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

我现在想创建一个名为 scriptUniqueWords 的数组,它只包含在 scriptEachWordInArray[=27= 中出现一次(换句话说是唯一的)的单词]

所以我希望我的 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])")}

}

您可以使用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: [=10=]) == 1 }.flatMap { [=10=] as? String }

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

在不保留顺序的情况下过滤掉唯一的单词

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

let scriptEachWordInArray = ["Silent", "night", "Holy", "night"]

var freqs: [String: Int] = [:]
scriptEachWordInArray.forEach { freqs[[=10=]] = (freqs[[=10=]] ?? 0) + 1 }

let scriptUniqueWords = freqs.flatMap { [=10=].1 == 1 ? [=10=].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[[=11=]] {
                frequencies[idx].1 += 1
            }
            else {
                seen[[=11=]] = frequencies.count
                frequencies.append(([=11=], 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[[=11=]].1 += 1 } ?? {
                seen[elem] = frequencies.count
                return frequencies.append((elem, 1))
            }()
        }
        return frequencies
    }
}

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

let scriptUniqueWords = scriptEachWordInArray.frequencies
    .flatMap { [=12=].1 == 1 ? [=12=].0 : nil }

print(scriptUniqueWords) // ["Silent", "Holy"]

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

let newArray = array.filter { !array.contains([=10=]) }

Swift

让我们试试。

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