我可能有一个像下面这样的数组:
[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或更高版本
我们还可以扩展RangeReplaceableCollection协议,以允许它也用于StringProtocol类型:
extension RangeReplaceableCollection where Element: Hashable {
var orderedSet: Self {
var set = Set<Element>()
return filter { set.insert($0).inserted }
}
mutating func removeDuplicates() {
var set = Set<Element>()
removeAll { !set.insert($0).inserted }
}
}
let integers = [1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]
let integersOrderedSet = integers.orderedSet // [1, 4, 2, 6, 24, 15, 60]
"abcdefabcghi".orderedSet // "abcdefghi"
"abcdefabcghi".dropFirst(3).orderedSet // "defabcghi"
变异的方法:
var string = "abcdefabcghi"
string.removeDuplicates()
string // "abcdefghi"
var substring = "abcdefabcdefghi".dropFirst(3) // "defabcdefghi"
substring.removeDuplicates()
substring // "defabcghi"
对于Swift 3,请点击这里
其他回答
Daniel Krom的Swift 2答案的更简洁的语法版本,使用了一个尾随闭包和简写参数名,这似乎是基于Airspeed Velocity的原始答案:
func uniq<S: SequenceType, E: Hashable where E == S.Generator.Element>(source: S) -> [E] {
var seen = [E: Bool]()
return source.filter { seen.updateValue(true, forKey: $0) == nil }
}
实现一个可以与uniq(_:)一起使用的自定义类型的示例(必须符合Hashable,因此符合Equatable,因为Hashable扩展了Equatable):
func ==(lhs: SomeCustomType, rhs: SomeCustomType) -> Bool {
return lhs.id == rhs.id // && lhs.someOtherEquatableProperty == rhs.someOtherEquatableProperty
}
struct SomeCustomType {
let id: Int
// ...
}
extension SomeCustomType: Hashable {
var hashValue: Int {
return id
}
}
在上面的代码中…
在==重载中使用的id可以是任何Equatable类型(或返回Equatable类型的方法,例如someMethodThatReturnsAnEquatableType())。注释掉的代码演示了扩展相等性检查,其中someOtherEquatableProperty是Equatable类型的另一个属性(但也可以是返回Equatable类型的方法)。
在hashValue计算属性中使用的id(必须符合Hashable)可以是任何Hashable(因此是Equatable)属性(或返回Hashable类型的方法)。
使用uniq(_:)的示例:
var someCustomTypes = [SomeCustomType(id: 1), SomeCustomType(id: 2), SomeCustomType(id: 3), SomeCustomType(id: 1)]
print(someCustomTypes.count) // 4
someCustomTypes = uniq(someCustomTypes)
print(someCustomTypes.count) // 3
斯威夫特5.7
使用有序集
您可以将具有重复元素的数组传递给以下通用函数,该函数处理有序Set并返回没有重复元素的新数组。
import Foundation
internal func withoutDuplicates<T>(_ array: [T]) -> [T] {
let orderedSet: NSMutableOrderedSet = []
var modifiedArray = [T]()
orderedSet.addObjects(from: array)
for i in 0...(orderedSet.count - 1) {
modifiedArray.append(orderedSet[i] as! T)
}
return modifiedArray
}
////////////////////////////////////////////////////////////
let arrayOfStrings: [String] = ["A","A","A","B","B","C","C"]
let arrayOfIntegers: [UInt8] = [1, 1, 1, 2, 2, 2, 3, 3]
let arrayOfBooleans: [Bool] = [true, false, false, true]
let ordered_01 = withoutDuplicates(arrayOfStrings)
let ordered_02 = withoutDuplicates(arrayOfIntegers)
let ordered_03 = withoutDuplicates(arrayOfBooleans)
结果:
// ordered_01 –––> ["A","B","C"]
// ordered_02 –––> [1, 2, 3]
// ordered_03 –––> [true, false]
使用无序集
如果新数组中元素的顺序对您来说并不重要,则在处理时使用无序集。无序集中的元素类型必须符合哈希协议。
import UIKit
fileprivate func noDuplicates<T: Hashable>(_ array: [T]) -> [T] {
var unorderedSet = Set<T>()
var modifiedArray: [T] = []
for i in 0...(array.count - 1) {
unorderedSet.insert(array[i])
}
for i in unorderedSet.indices {
modifiedArray.append(unorderedSet[i])
}
return modifiedArray
}
////////////////////////////////////////////////////////////
let arrayOfInts: [Int] = [10, 5, 7, 200, -500, 10, 7, 5]
let arrayOfStrs: [String] = ["A","A","A","B","B","C","C"]
let arrayOfBools: [Bool] = [true, false, false, true]
let unordered_01 = noDuplicates(arrayOfInts)
let unordered_02 = noDuplicates(arrayOfStrs)
let unordered_03 = noDuplicates(arrayOfBools)
结果:
// unordered_01 –––> [200, 7, 10, -500, 5]
// unordered_02 –––> ["B", "C", "A"]
// unordered_03 –––> [false, true]
从数组中删除重复项的另一个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中。
如果项目在集合中,过滤器将从最终结果中排除它。
我创建了一个时间复杂度为o(n)的高阶函数。另外,像map这样的功能可以返回您想要的任何类型。
extension Sequence {
func distinct<T,U>(_ provider: (Element) -> (U, T)) -> [T] where U: Hashable {
var uniqueKeys = Set<U>()
var distintValues = [T]()
for object in self {
let transformed = provider(object)
if !uniqueKeys.contains(transformed.0) {
distintValues.append(transformed.1)
uniqueKeys.insert(transformed.0)
}
}
return distintValues
}
}
斯威夫特4. x:
extension Sequence where Iterator.Element: Hashable {
func unique() -> [Iterator.Element] {
return Array(Set<Iterator.Element>(self))
}
func uniqueOrdered() -> [Iterator.Element] {
return reduce([Iterator.Element]()) { $0.contains($1) ? $0 : $0 + [$1] }
}
}
用法:
["Ljubljana", "London", "Los Angeles", "Ljubljana"].unique()
or
["Ljubljana", "London", "Los Angeles", "Ljubljana"].uniqueOrdered()