我可能有一个像下面这样的数组:
[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 2及以上:
extension Array where Element:Equatable {
func removeDuplicates() -> [Element] {
var result = [Element]()
for value in self {
if result.contains(value) == false {
result.append(value)
}
}
return result
}
}
这非常简单。可以这样调用:
let arrayOfInts = [2, 2, 4, 4]
print(arrayOfInts.removeDuplicates()) // Prints: [2, 4]
基于属性的过滤
要根据属性筛选数组,你可以使用这个方法:
extension Array {
func filterDuplicates(@noescape includeElement: (lhs:Element, rhs:Element) -> Bool) -> [Element]{
var results = [Element]()
forEach { (element) in
let existingElements = results.filter {
return includeElement(lhs: element, rhs: $0)
}
if existingElements.count == 0 {
results.append(element)
}
}
return results
}
}
你可以这样调用它:
let filteredElements = myElements.filterDuplicates { $0.PropertyOne == $1.PropertyOne && $0.PropertyTwo == $1.PropertyTwo }
其他回答
你可以很容易地转换为一个Set和一个数组:
let unique = Array(Set(originals))
这并不能保证保持数组的原始顺序。
这只是一个非常简单和方便的实现。具有相等元素的数组扩展中的计算属性。
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
}
}
这里我对对象做了O(n)解。不是少行解决方案,而是……
struct DistinctWrapper <T>: Hashable {
var underlyingObject: T
var distinctAttribute: String
var hashValue: Int {
return distinctAttribute.hashValue
}
}
func distinct<S : SequenceType, T where S.Generator.Element == T>(source: S,
distinctAttribute: (T) -> String,
resolution: (T, T) -> T) -> [T] {
let wrappers: [DistinctWrapper<T>] = source.map({
return DistinctWrapper(underlyingObject: $0, distinctAttribute: distinctAttribute($0))
})
var added = Set<DistinctWrapper<T>>()
for wrapper in wrappers {
if let indexOfExisting = added.indexOf(wrapper) {
let old = added[indexOfExisting]
let winner = resolution(old.underlyingObject, wrapper.underlyingObject)
added.insert(DistinctWrapper(underlyingObject: winner, distinctAttribute: distinctAttribute(winner)))
} else {
added.insert(wrapper)
}
}
return Array(added).map( { return $0.underlyingObject } )
}
func == <T>(lhs: DistinctWrapper<T>, rhs: DistinctWrapper<T>) -> Bool {
return lhs.hashValue == rhs.hashValue
}
// tests
// case : perhaps we want to get distinct addressbook list which may contain duplicated contacts like Irma and Irma Burgess with same phone numbers
// solution : definitely we want to exclude Irma and keep Irma Burgess
class Person {
var name: String
var phoneNumber: String
init(_ name: String, _ phoneNumber: String) {
self.name = name
self.phoneNumber = phoneNumber
}
}
let persons: [Person] = [Person("Irma Burgess", "11-22-33"), Person("Lester Davidson", "44-66-22"), Person("Irma", "11-22-33")]
let distinctPersons = distinct(persons,
distinctAttribute: { (person: Person) -> String in
return person.phoneNumber
},
resolution:
{ (p1, p2) -> Person in
return p1.name.characters.count > p2.name.characters.count ? p1 : p2
}
)
// distinctPersons contains ("Irma Burgess", "11-22-33") and ("Lester Davidson", "44-66-22")
从数组中删除重复项的另一个Swift 3.0解决方案。该解决方案改进了许多已经提出的其他解决方案:
保留输入数组中元素的顺序 线性复杂度O(n):单通滤波器O(n) +集插入O(1)
给定整数数组:
let numberArray = [10, 1, 2, 3, 2, 1, 15, 4, 5, 6, 7, 3, 2, 12, 2, 5, 5, 6, 10, 7, 8, 3, 3, 45, 5, 15, 6, 7, 8, 7]
功能代码:
func orderedSet<T: Hashable>(array: Array<T>) -> Array<T> {
var unique = Set<T>()
return array.filter { element in
return unique.insert(element).inserted
}
}
orderedSet(array: numberArray) // [10, 1, 2, 3, 15, 4, 5, 6, 7, 12, 8, 45]
数组扩展代码:
extension Array where Element:Hashable {
var orderedSet: Array {
var unique = Set<Element>()
return filter { element in
return unique.insert(element).inserted
}
}
}
numberArray.orderedSet // [10, 1, 2, 3, 15, 4, 5, 6, 7, 12, 8, 45]
这段代码利用了Set上的插入操作返回的结果,该操作在O(1)上执行,并返回一个元组,指示该项是否被插入,或者该项是否已经存在于Set中。
如果项目在集合中,过滤器将从最终结果中排除它。
Swift 3/ Swift 4/ Swift 5
只需要一行代码就可以省略数组副本而不影响顺序:
let filteredArr = Array(NSOrderedSet(array: yourArray))