我可能有一个像下面这样的数组:
[1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]
或者,实际上,任何类似类型的数据部分的序列。我要做的是确保每个相同的元素只有一个。例如,上面的数组将变成:
[1, 4, 2, 6, 24, 15, 60]
请注意,删除了2、6和15的重复项,以确保每个相同的元素中只有一个。Swift是否提供了一种容易做到这一点的方法,还是我必须自己做?
我可能有一个像下面这样的数组:
[1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]
或者,实际上,任何类似类型的数据部分的序列。我要做的是确保每个相同的元素只有一个。例如,上面的数组将变成:
[1, 4, 2, 6, 24, 15, 60]
请注意,删除了2、6和15的重复项,以确保每个相同的元素中只有一个。Swift是否提供了一种容易做到这一点的方法,还是我必须自己做?
当前回答
如果你需要值排序,这是工作(Swift 4)
let sortedValues = Array(Set(Array)).sorted()
其他回答
受https://www.swiftbysundell.com/posts/the-power-of-key-paths-in-swift的启发,我们可以声明一个更强大的工具,它能够过滤任何keyPath上的唯一性。感谢Alexander关于复杂性的各种答案的评论,下面的解决方案应该是最优的。
Non-mutating解决方案
我们扩展了一个函数,它可以过滤任意keyPath上的唯一性:
extension RangeReplaceableCollection {
/// Returns a collection containing, in order, the first instances of
/// elements of the sequence that compare equally for the keyPath.
func unique<T: Hashable>(for keyPath: KeyPath<Element, T>) -> Self {
var unique = Set<T>()
return filter { unique.insert($0[keyPath: keyPath]).inserted }
}
}
注意:在你的对象不符合RangeReplaceableCollection,但符合Sequence的情况下,你可以有这个额外的扩展,但返回类型将始终是一个数组:
extension Sequence {
/// Returns an array containing, in order, the first instances of
/// elements of the sequence that compare equally for the keyPath.
func unique<T: Hashable>(for keyPath: KeyPath<Element, T>) -> [Element] {
var unique = Set<T>()
return filter { unique.insert($0[keyPath: keyPath]).inserted }
}
}
使用
如果我们想要元素本身的唯一性,如问题中所示,我们使用keyPath \.self:
let a = [1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]
let b = a.unique(for: \.self)
/* b is [1, 4, 2, 6, 24, 15, 60] */
如果我们想要其他东西的唯一性(比如对象集合的id),那么我们使用我们选择的keyPath:
let a = [CGPoint(x: 1, y: 1), CGPoint(x: 2, y: 1), CGPoint(x: 1, y: 2)]
let b = a.unique(for: \.y)
/* b is [{x 1 y 1}, {x 1 y 2}] */
变异的解决方案
我们扩展了一个变异函数,它能够过滤任意keyPath上的唯一性:
extension RangeReplaceableCollection {
/// Keeps only, in order, the first instances of
/// elements of the collection that compare equally for the keyPath.
mutating func uniqueInPlace<T: Hashable>(for keyPath: KeyPath<Element, T>) {
var unique = Set<T>()
removeAll { !unique.insert($0[keyPath: keyPath]).inserted }
}
}
使用
如果我们想要元素本身的唯一性,如问题中所示,我们使用keyPath \.self:
var a = [1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]
a.uniqueInPlace(for: \.self)
/* a is [1, 4, 2, 6, 24, 15, 60] */
如果我们想要其他东西的唯一性(比如对象集合的id),那么我们使用我们选择的keyPath:
var a = [CGPoint(x: 1, y: 1), CGPoint(x: 2, y: 1), CGPoint(x: 1, y: 2)]
a.uniqueInPlace(for: \.y)
/* a is [{x 1 y 1}, {x 1 y 2}] */
在数组中保留唯一值和排序。
(使用Swift 3)
var top3score: [Int] = []
outerLoop: for i in 0..<top10score.count {
dlog(message: String(top10score[i]))
if top3score.count == 3 {
break
}
for aTop3score in top3score {
if aTop3score == top10score[i] {
continue outerLoop
}
}
top3score.append(top10score[i])
}
print("top10score is \(top10score)") //[14, 5, 5, 5, 3, 3, 2, 2, 2, 2]
print("top3score is \(top3score)") //[14, 5, 3]
包含相等性检查,而插入检查哈希,最安全的检查方式如下:
extension Array where Element: Hashable {
/// Big O(N) version. Updated since @Adrian's comment.
var uniques: Array {
// Go front to back, add element to buffer if it isn't a repeat.
var buffer: [Element] = []
var dictionary: [Element: Int] = [:]
for element in self where dictionary[element] == nil {
buffer.append(element)
dictionary[element] = 1
}
return buffer
}
}
首先将数组的所有元素添加到NSOrderedSet中。 这将删除数组中的所有重复项。 再次将这个orderedset转换为一个数组。
做……
例子
let array = [1,1,1,1,2,2,2,2,4,6,8]
let orderedSet : NSOrderedSet = NSOrderedSet(array: array)
let arrayWithoutDuplicates : NSArray = orderedSet.array as NSArray
输出arraywithoutduplates - [1,2,4,6,8]
为此,我做了一个尽可能简单的扩展。
extension Array where Element: Equatable {
func containsHowMany(_ elem: Element) -> Int {
return reduce(0) { $1 == elem ? $0 + 1 : $0 }
}
func duplicatesRemoved() -> Array {
return self.filter { self.containsHowMany($0) == 1 }
}
mutating func removeDuplicates() {
self = self.duplicatesRemoved(()
}
}
您可以使用duplicatesRemoved()来获取一个新数组,它的重复元素将被删除,或者使用removeduplicate()来改变自身。看到的:
let arr = [1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6, 6, 6, 7, 8]
let noDuplicates = arr.duplicatesRemoved()
print(arr) // [1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6, 6, 6, 7, 8]
print(noDuplicates) // [1, 2, 3, 4, 5, 6, 7, 8]
arr.removeDuplicates()
print(arr) // [1, 2, 3, 4, 5, 6, 7, 8]