我可能有一个像下面这样的数组:
[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是否提供了一种容易做到这一点的方法,还是我必须自己做?
当前回答
这里有一个解决方案
不使用传统NS类型 对于O(n)来说是相当快的 简洁 保持元素顺序
extension Array where Element: Hashable {
var uniqueValues: [Element] {
var allowed = Set(self)
return compactMap { allowed.remove($0) }
}
}
其他回答
这只是一个非常简单和方便的实现。具有相等元素的数组扩展中的计算属性。
extension Array where Element: Equatable {
/// Array containing only _unique_ elements.
var unique: [Element] {
var result: [Element] = []
for element in self {
if !result.contains(element) {
result.append(element)
}
}
return result
}
}
斯威夫特4
保证继续订购。
extension Array where Element: Equatable {
func removingDuplicates() -> Array {
return reduce(into: []) { result, element in
if !result.contains(element) {
result.append(element)
}
}
}
}
下面是SequenceType上的一个类别,它保留了数组的原始顺序,但使用Set来进行contains查找,以避免数组的contains(_:)方法上的O(n)代价。
public extension Sequence where Element: Hashable {
/// Return the sequence with all duplicates removed.
///
/// i.e. `[ 1, 2, 3, 1, 2 ].uniqued() == [ 1, 2, 3 ]`
///
/// - note: Taken from stackoverflow.com/a/46354989/3141234, as
/// per @Alexander's comment.
func uniqued() -> [Element] {
var seen = Set<Element>()
return self.filter { seen.insert($0).inserted }
}
}
如果你不是Hashable或Equatable,你可以传入一个谓词来进行相等性检查:
extension Sequence {
/// Return the sequence with all duplicates removed.
///
/// Duplicate, in this case, is defined as returning `true` from `comparator`.
///
/// - note: Taken from stackoverflow.com/a/46354989/3141234
func uniqued(comparator: @escaping (Element, Element) throws -> Bool) rethrows -> [Element] {
var buffer: [Element] = []
for element in self {
// If element is already in buffer, skip to the next element
if try buffer.contains(where: { try comparator(element, $0) }) {
continue
}
buffer.append(element)
}
return buffer
}
}
现在,如果你没有Hashable,但是是Equatable,你可以使用这个方法:
extension Sequence where Element: Equatable {
/// Return the sequence with all duplicates removed.
///
/// i.e. `[ 1, 2, 3, 1, 2 ].uniqued() == [ 1, 2, 3 ]`
///
/// - note: Taken from stackoverflow.com/a/46354989/3141234
func uniqued() -> [Element] {
return self.uniqued(comparator: ==)
}
}
最后,你可以添加一个unique的关键路径版本,如下所示:
extension Sequence {
/// Returns the sequence with duplicate elements removed, performing the comparison using the property at
/// the supplied keypath.
///
/// i.e.
///
/// ```
/// [
/// MyStruct(value: "Hello"),
/// MyStruct(value: "Hello"),
/// MyStruct(value: "World")
/// ].uniqued(\.value)
/// ```
/// would result in
///
/// ```
/// [
/// MyStruct(value: "Hello"),
/// MyStruct(value: "World")
/// ]
/// ```
///
/// - note: Taken from stackoverflow.com/a/46354989/3141234
///
func uniqued<T: Equatable>(_ keyPath: KeyPath<Element, T>) -> [Element] {
self.uniqued { $0[keyPath: keyPath] == $1[keyPath: keyPath] }
}
}
你可以把这两个都放在你的应用程序中,Swift会根据你的序列的迭代器选择正确的一个。元素类型。
对于El Capitan,您可以扩展此方法以包括多个键盘,如下所示:
/// Returns the sequence with duplicate elements removed, performing the comparison using the property at
/// the supplied keypaths.
///
/// i.e.
///
/// ```
/// [
/// MyStruct(value1: "Hello", value2: "Paula"),
/// MyStruct(value1: "Hello", value2: "Paula"),
/// MyStruct(value1: "Hello", value2: "Bean"),
/// MyStruct(value1: "World", value2: "Sigh")
/// ].uniqued(\.value1, \.value2)
/// ```
/// would result in
///
/// ```
/// [
/// MyStruct(value1: "Hello", value2: "Paula"),
/// MyStruct(value1: "Hello", value2: "Bean"),
/// MyStruct(value1: "World", value2: "Sigh")
/// ]
/// ```
///
/// - note: Taken from stackoverflow.com/a/46354989/3141234
///
func uniqued<T: Equatable, U: Equatable>(_ keyPath1: KeyPath<Element, T>, _ keyPath2: KeyPath<Element, U>) -> [Element] {
self.uniqued {
$0[keyPath: keyPath1] == $1[keyPath: keyPath1] && $0[keyPath: keyPath2] == $1[keyPath: keyPath2]
}
}
但是(恕我直言)你最好把你自己的block传递给self.unique。
如果你想保持秩序,那么就用这个
let fruits = ["apple", "pear", "pear", "banana", "apple"]
let orderedNoDuplicates = Array(NSOrderedSet(array: fruits).map({ $0 as! String }))
你可以很容易地转换为一个Set和一个数组:
let unique = Array(Set(originals))
这并不能保证保持数组的原始顺序。