我可能有一个如下所示的数组:
[1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]
或者,实际上,任何类似数据类型的序列。我想要做的是确保每个相同的元素只有一个。例如,上面的数组将成为:
[1, 4, 2, 6, 24, 15, 60]
请注意,删除了重复的2,6和15,以确保每个相同的元素只有一个。斯威夫特是否提供了一种方便的方法,或者我必须自己做这件事吗?
答案 0 :(得分:406)
您可以很容易地再次转换为集合并返回数组:
let unique = Array(Set(originals))
这不能保证维持数组的原始顺序。
答案 1 :(得分:99)
你可以自己滚动,例如像这样(使用Set 更新了Swift 1.2):
func uniq<S : SequenceType, T : Hashable where S.Generator.Element == T>(source: S) -> [T] {
var buffer = [T]()
var added = Set<T>()
for elem in source {
if !added.contains(elem) {
buffer.append(elem)
added.insert(elem)
}
}
return buffer
}
let vals = [1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]
let uniqueVals = uniq(vals) // [1, 4, 2, 6, 24, 15, 60]
Swift 3版本:
func uniq<S : Sequence, T : Hashable>(source: S) -> [T] where S.Iterator.Element == T {
var buffer = [T]()
var added = Set<T>()
for elem in source {
if !added.contains(elem) {
buffer.append(elem)
added.insert(elem)
}
}
return buffer
}
答案 2 :(得分:59)
这里有很多答案,但我错过了这个简单的扩展,适用于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 }
答案 3 :(得分:52)
这会获取本页面上已有的一些好消息,并在可能的情况下应用Hashable / Set方法,否则将回退到Equatable代码。
Equatable
分机Hashable
的快速4变化保持不变
public extension Sequence where Element: Equatable {
var uniqueElements: [Element] {
return self.reduce(into: []) {
uniqueElements, element in
if !uniqueElements.contains(element) {
uniqueElements.append(element)
}
}
}
}
Swift 3
public extension Sequence where Iterator.Element: Hashable {
var uniqueElements: [Iterator.Element] {
return Array( Set(self) )
}
}
public extension Sequence where Iterator.Element: Equatable {
var uniqueElements: [Iterator.Element] {
return self.reduce([]){
uniqueElements, element in
uniqueElements.contains(element)
? uniqueElements
: uniqueElements + [element]
}
}
}
Swift 2
public extension SequenceType where Generator.Element: Hashable {
var uniqueElements: [Generator.Element] {
return Array(
Set(self)
)
}
}
public extension SequenceType where Generator.Element: Equatable {
var uniqueElements: [Generator.Element] {
return self.reduce([]){uniqueElements, element in
uniqueElements.contains(element)
? uniqueElements
: uniqueElements + [element]
}
}
}
答案 4 :(得分:47)
Swift 3.0
let uniqueUnordered = Array(Set(array))
let uniqueOrdered = Array(NSOrderedSet(array: array))
答案 5 :(得分:36)
将集合元素约束到 user_id c
------------------
1 1
2 1
,您可以使用contains:
Equatable
另一种选择是将集合元素约束为Hashable,并使用集合来控制必须映射到结果中的元素:
extension Collection where Element: Equatable {
var orderedSet: [Element] {
var array: [Element] = []
return compactMap {
if array.contains($0) {
return nil
} else {
array.append($0)
return $0
}
}
}
}
使用过滤器:
extension Collection where Element: Hashable {
var orderedSet: [Element] {
var set = Set<Element>()
return compactMap { set.insert($0).inserted ? $0 : nil }
}
}
或使用extension Collection where Element: Hashable {
var orderedSet: [Element] {
var set = Set<Element>()
return filter { set.insert($0).inserted }
}
}
:
NSOrderedSet
使用Swift4集合方法extension Array where Element: Hashable {
var orderedSet: Array {
return NSOrderedSet(array: self).array as? Array ?? []
}
}
:
reduce(into:)
extension Collection where Element: Hashable {
var orderedSet: [Element] {
var set: Set<Element> = []
return reduce(into: []) { set.insert($1).inserted ? $0.append($1) : () }
}
}
Swift 4或更高版本我们还可以扩展let integers = [1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]
let integersOrderedSet = integers.orderedSet // [1, 4, 2, 6, 24, 15, 60]
协议以允许它与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 }
}
}
变异方法
"abcdefabcghi".orderedSet // "abcdefghi"
"abcdefabcghi".dropFirst(3).orderedSet // "defabcghi"
答案 6 :(得分:25)
Swift 4
保证继续订购。
extension Array where Element: Equatable {
func removingDuplicates() -> Array {
return reduce(into: []) { result, element in
if !result.contains(element) {
result.append(element)
}
}
}
}
答案 7 :(得分:25)
Swift 4
public extension Array where Element: Hashable {
func uniqued() -> [Element] {
var seen = Set<Element>()
return filter{ seen.insert($0).inserted }
}
}
每次insert
的尝试也会返回一个元组:(inserted: Bool, memberAfterInsert: Set.Element)
。见documentation。
使用返回的值有助于我们避免循环或执行任何其他操作。
答案 8 :(得分:12)
来自here的替代(如果不是最佳)解决方案使用不可变类型而不是变量:
func deleteDuplicates<S: ExtensibleCollectionType where S.Generator.Element: Equatable>(seq:S)-> S {
let s = reduce(seq, S()){
ac, x in contains(ac,x) ? ac : ac + [x]
}
return s
}
将Jean-Pillippe的强制性方法与功能性方法进行对比。
作为奖励,此功能适用于字符串和数组!
编辑:这个答案是2014年针对Swift 1.0撰写的(在Set
可用于Swift之前)。它不需要Hashable一致性和以二次方式运行。
答案 9 :(得分:12)
此处&#39; SequenceType
上的类别保留了数组的原始顺序,但使用Set
执行contains
查找以避免O(n)
费用在Array的contains(_:)
方法上。
public extension Array where Element: Hashable {
/// Return the array 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.
public func uniqued() -> [Element] {
var seen = Set<Element>()
return self.filter { seen.insert($0).inserted }
}
}
或者如果你没有Hashable,你可以这样做:
public extension Sequence where Iterator.Element: Equatable {
public func uniqued() -> [Iterator.Element] {
var buffer: [Iterator.Element] = []
for element in self {
guard !buffer.contains(element) else { continue }
buffer.append(element)
}
return buffer
}
}
您可以将这两者都粘贴到您的应用中,Swift会根据您的序列选择正确的Iterator.Element
类型。
答案 10 :(得分:10)
使用 uniq 功能回答:
func uniq<S: SequenceType, E: Hashable where E==S.Generator.Element>(source: S) -> [E] {
var seen: [E:Bool] = [:]
return source.filter({ (v) -> Bool in
return seen.updateValue(true, forKey: v) == nil
})
}
使用:
var test = [1,2,3,4,5,6,7,8,9,9,9,9,9,9]
print(uniq(test)) //1,2,3,4,5,6,7,8,9
答案 11 :(得分:9)
Swift 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()
或
["Ljubljana", "London", "Los Angeles", "Ljubljana"].uniqueOrdered()
答案 12 :(得分:6)
您可以直接使用set集合删除重复项,然后将其强制转换为数组
var myArray = [1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]
var mySet = Set<Int>(myArray)
myArray = Array(mySet) // [2, 4, 60, 6, 15, 24, 1]
然后您可以根据需要订购数组
myArray.sort{$0 < $1} // [1, 2, 4, 6, 15, 24, 60]
答案 13 :(得分:6)
另一个Swift 3.0解决方案,用于从阵列中删除重复项。该解决方案改进了以下提出的许多其他解决方案:
给定整数数组:
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]
此代码利用insert
上Set
操作返回的结果,该操作在O(1)
上执行,并返回一个元组,指示项目是否已插入或是否已存在在集合中。
如果该项目在集合中,filter
会将其从最终结果中排除。
答案 14 :(得分:6)
在Swift 5中
var array: [String] = ["Aman", "Sumit", "Aman", "Sumit", "Mohan", "Mohan", "Amit"]
let uniq = Array(Set(array))
print(uniq)
输出将为
["Sumit", "Mohan", "Amit", "Aman"]
答案 15 :(得分:5)
受https://www.swiftbysundell.com/posts/the-power-of-key-paths-in-swift的启发,我们可以声明一个更强大的工具,该工具能够过滤任何keyPath的唯一性。感谢Alexander对复杂性的各种回答,下面的解决方案应该是最佳的。
我们扩展了一个功能,该功能能够过滤任何keyPath上的唯一性:
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}] */
答案 16 :(得分:4)
extension Sequence where Iterator.Element: Hashable {
func unique() -> [Iterator.Element] {
var seen: [Iterator.Element: Bool] = [:]
return self.filter { seen.updateValue(true, forKey: $0) == nil }
}
}
答案 17 :(得分:3)
func removeDublicate (ab: [Int]) -> [Int] {
var answer1:[Int] = []
for i in ab {
if !answer1.contains(i) {
answer1.append(i)
}}
return answer1
}
用法:
let f = removeDublicate(ab: [1,2,2])
print(f)
答案 18 :(得分:3)
对于元素既不Hashable也不Comparable(例如复杂对象,字典或结构)的数组,此扩展提供了一种删除重复项的通用方法:
market_price_cb
您不必费心使用值Hashable,它允许您使用不同的字段组合来实现唯一性。
注意:有关更强大的方法,请参阅下面评论中Coeur提出的解决方案。
stackoverflow.com/a/55684308/1033581
[编辑] Swift 4替代
使用Swift 4.2,您可以使用Hasher类更轻松地构建哈希。可以更改上述扩展名以利用此功能:
extension Array
{
func filterDuplicate<T:Hashable>(_ keyValue:(Element)->T) -> [Element]
{
var uniqueKeys = Set<T>()
return filter{uniqueKeys.insert(keyValue($0)).inserted}
}
func filterDuplicate<T>(_ keyValue:(Element)->T) -> [Element]
{
return filterDuplicate{"\(keyValue($0))"}
}
}
// example usage: (for a unique combination of attributes):
peopleArray = peopleArray.filterDuplicate{ ($0.name, $0.age, $0.sex) }
or...
peopleArray = peopleArray.filterDuplicate{ "\(($0.name, $0.age, $0.sex))" }
调用语法略有不同,因为闭包接收一个附加参数,该参数包含散列可变数量值的函数(必须单独使用Hashable)
extension Array
{
func filterDuplicate(_ keyValue:((AnyHashable...)->AnyHashable,Element)->AnyHashable) -> [Element]
{
func makeHash(_ params:AnyHashable ...) -> AnyHashable
{
var hash = Hasher()
params.forEach{ hash.combine($0) }
return hash.finalize()
}
var uniqueKeys = Set<AnyHashable>()
return filter{uniqueKeys.insert(keyValue(makeHash,$0)).inserted}
}
}
它也可以使用单个唯一性值(使用$ 1并忽略$ 0)。
peopleArray = peopleArray.filterDuplicate{ $0($1.name, $1.age, $1.sex) }
答案 19 :(得分:3)
这是一个解决方案
git mv -f "example.png " example.png
git commit -m "Removed trailing space from filename"
类型NS
的速度相当快O(n)
答案 20 :(得分:3)
稍微简洁一点Daniel Krom's Swift 2 answer的语法版本,使用尾随闭包和简写参数名称,它似乎基于Airspeed Velocity's original answer:
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
类型的方法)。
id
,在hashValue
计算属性中使用(符合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
答案 21 :(得分:2)
基于@ Jean-Philippe Pellet的数组扩展名答案的简短缩写版本:
extension Array where Element: Hashable {
var uniques: Array {
var added = Set<Element>()
return filter { element in
defer { added.insert(element) }
return !added.contains(element)
}
}
}
答案 22 :(得分:2)
这只是一个非常简单方便的实现。具有equatable元素的Array扩展中的计算属性。
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
}
}
答案 23 :(得分:2)
这里我已经为对象做了一些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")
答案 24 :(得分:2)
我使用了@ Jean-Philippe Pellet的答案并制作了一个Array扩展,它对数组进行了类似集合的操作,同时保持了元素的顺序。
/// Extensions for performing set-like operations on lists, maintaining order
extension Array where Element: Hashable {
func unique() -> [Element] {
var seen: [Element:Bool] = [:]
return self.filter({ seen.updateValue(true, forKey: $0) == nil })
}
func subtract(takeAway: [Element]) -> [Element] {
let set = Set(takeAway)
return self.filter({ !set.contains($0) })
}
func intersect(with: [Element]) -> [Element] {
let set = Set(with)
return self.filter({ set.contains($0) })
}
}
答案 25 :(得分:2)
您始终可以使用词典,因为词典只能包含唯一值。例如:
var arrayOfDates: NSArray = ["15/04/01","15/04/01","15/04/02","15/04/02","15/04/03","15/04/03","15/04/03"]
var datesOnlyDict = NSMutableDictionary()
var x = Int()
for (x=0;x<(arrayOfDates.count);x++) {
let date = arrayOfDates[x] as String
datesOnlyDict.setValue("foo", forKey: date)
}
let uniqueDatesArray: NSArray = datesOnlyDict.allKeys // uniqueDatesArray = ["15/04/01", "15/04/03", "15/04/02"]
println(uniqueDatesArray.count) // = 3
如您所见,生成的数组并不总是处于'顺序'。如果您希望对数组进行排序/排序,请添加:
var sortedArray = sorted(datesOnlyArray) {
(obj1, obj2) in
let p1 = obj1 as String
let p2 = obj2 as String
return p1 < p2
}
println(sortedArray) // = ["15/04/01", "15/04/02", "15/04/03"]
答案 26 :(得分:2)
Swift 3 / Swift 4 / Swift 5
仅需一行代码即可在不影响顺序的情况下省略数组重复项:
let filteredArr = Array(NSOrderedSet(array: yourArray))
答案 27 :(得分:2)
如果您需要对值进行排序,则可以使用(Swift 4)
let sortedValues = Array(Set(array)).sorted()
答案 28 :(得分:1)
func removeDuplicates(_ nums: inout [Int]) -> Int {
nums = Set(nums).sorted()
return nums.count
}
示例
var arr = [1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9]
removeDuplicates(&arr)
print(arr) // [1,2,3,4,5,6,7,8,9]
答案 29 :(得分:1)
这是Swift 4.2及以下代码中最简单的方法
let keyarray:NSMutableArray = NSMutableArray()
for object in dataArr
{
if !keysArray.contains(object){
keysArray.add(object)
}
}
print(keysArray)
答案 30 :(得分:1)
完成。...
示例
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
arrayWithoutDuplicates的输出-[1,2,4,6,8]
答案 31 :(得分:1)
我为此目的做了一个尽可能简单的扩展。
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()
获取一个新数组,删除其重复元素,或removeDuplicates()
自我变异。参见:
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]
答案 32 :(得分:1)
我认为这是了解逻辑本身的更好方法
var arrayOfInts = [2, 2, 4, 4]
var mainArray = [Int]()
for value in arrayOfInts {
if mainArray.contains(value) == false {
mainArray.append(value)
print("mainArray:\(mainArray)")
}}
答案 33 :(得分:1)
如果您还想保留订单,请使用此
True
答案 34 :(得分:1)
在Swift 3.0中,我发现最简单,最快速的解决方案是在保持顺序的同时消除重复元素:
extension Array where Element:Hashable {
var unique: [Element] {
var set = Set<Element>() //the unique list kept in a Set for fast retrieval
var arrayOrdered = [Element]() //keeping the unique list of elements but ordered
for value in self {
if !set.contains(value) {
set.insert(value)
arrayOrdered.append(value)
}
}
return arrayOrdered
}
}
答案 35 :(得分:1)
让我建议一个类似于Scott Gardner's answer的答案,但使用reduce更简洁的语法。 此解决方案从自定义对象数组中删除重复项(保持初始顺序)
// Custom Struct. Can be also class.
// Need to be `equitable` in order to use `contains` method below
struct CustomStruct : Equatable {
let name: String
let lastName : String
}
// conform to Equatable protocol. feel free to change the logic of "equality"
func ==(lhs: CustomStruct, rhs: CustomStruct) -> Bool {
return (lhs.name == rhs.name && lhs.lastName == rhs.lastName)
}
let categories = [CustomStruct(name: "name1", lastName: "lastName1"),
CustomStruct(name: "name2", lastName: "lastName1"),
CustomStruct(name: "name1", lastName: "lastName1")]
print(categories.count) // prints 3
// remove duplicates (and keep initial order of elements)
let uniq1 : [CustomStruct] = categories.reduce([]) { $0.contains($1) ? $0 : $0 + [$1] }
print(uniq1.count) // prints 2 - third element has removed
如果你想知道这种减少魔法是如何工作的 - 这里完全相同,但使用更多扩展的减少语法
let uniq2 : [CustomStruct] = categories.reduce([]) { (result, category) in
var newResult = result
if (newResult.contains(category)) {}
else {
newResult.append(category)
}
return newResult
}
uniq2.count // prints 2 - third element has removed
您只需将此代码复制粘贴到Swift Playground中即可玩游戏。
答案 36 :(得分:1)
正如 WWDC 2021 所指出的,Swift 拥有社区开发的算法、集合和数字包。 Algorithms 包具有 uniqued()
算法。
这些还不是 Swift 标准库的一部分。您目前可以从 Apple 的 Github 页面下载它们和/或通过 Swift Package Manager 安装它们。
WWDC 视频:
https://developer.apple.com/videos/play/wwdc2021/10256/
Github 页面:
https://github.com/apple/swift-algorithms
uniqued()
和 uniqued(on:)
文档:
https://github.com/apple/swift-algorithms/blob/main/Guides/Unique.md
答案 37 :(得分:0)
最简单的方法是使用NSOrderedSet,它存储唯一元素并保留元素顺序。像:
func removeDuplicates(from items: [Int]) -> [Int] {
let uniqueItems = NSOrderedSet(array: items)
return (uniqueItems.array as? [Int]) ?? []
}
let arr = [1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]
removeDuplicates(from: arr)
答案 38 :(得分:0)
我创建了一个高阶函数,其时间复杂度为o(n)。同样,地图等功能可以返回您想要的任何类型。
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
}
}
答案 39 :(得分:0)
我的解决方案,似乎可以在O(n)时间内完成,因为哈希映射访问为O(1),而过滤器为O(n)。它还使用by闭包来选择属性,通过该属性可以依次区分元素。
extension Sequence {
func distinct<T: Hashable>(by: (Element) -> T) -> [Element] {
var seen: [T: Bool] = [:]
return self.filter { seen.updateValue(true, forKey: by($0)) == nil }
}
}
答案 40 :(得分:0)
像功能程序员一样:)
要根据元素是否已经存在来过滤列表,需要索引。您可以使用enumerated
获取索引,并使用map
返回值列表。
let unique = myArray
.enumerated()
.filter{ myArray.firstIndex(of: $0.1) == $0.0 }
.map{ $0.1 }
这保证了订单。如果您不介意顺序,那么Array(Set(myArray))
的现有答案会更简单,也可能更有效。
答案 41 :(得分:0)
这是一种使用自定义匹配函数使序列唯一的更灵活的方法。
extension Sequence where Iterator.Element: Hashable {
func unique(matching: (Iterator.Element, Iterator.Element) -> Bool) -> [Iterator.Element] {
var uniqueArray: [Iterator.Element] = []
forEach { element in
let isUnique = uniqueArray.reduce(true, { (result, item) -> Bool in
return result && matching(element, item)
})
if isUnique {
uniqueArray.append(element)
}
}
return uniqueArray
}
}
答案 42 :(得分:0)
保留数组中的唯一值和保留排序。
(使用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]
答案 43 :(得分:0)
我相信通过删除它的值来提供uniq()
和uniqInPlace()
函数来改变数组是一件好事。这类似于Swift提供的sort()
和sortInPlace()
函数。此外,由于它是一个数组,它应该保持元素的原始顺序。
extension Array where Element: Equatable {
public func uniq() -> [Element] {
var arrayCopy = self
arrayCopy.uniqInPlace()
return arrayCopy
}
mutating public func uniqInPlace() {
var seen = [Element]()
var index = 0
for element in self {
if seen.contains(element) {
removeAtIndex(index)
} else {
seen.append(element)
index++
}
}
}
}
您只能在变量数组(即uniqInPlace()
)上使用var
,因为您无法改变常量数组(即let
)。
一些用法示例:
var numbers = [1, 6, 2, 2, 4, 1, 5]
numbers.uniqInPlace() // array is now [1, 6, 2, 4, 5]
let strings = ["Y", "Z", "A", "Y", "B", "Y", "Z"]
let uniqStrings = strings.uniq() // uniqStrings is now ["Y", "Z", "A", "B"]
答案 44 :(得分:-1)
这适用于Swift 4,如果您不希望/需要将结果转换为数组,但可以使用Set。结果默认情况下没有排序,但您可以使用sorted()返回一个数组,如print语句所示。
let array = [1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]
var result = Set<Int>()
_ = array.map{ result.insert($0) }
print(result.sorted()) // [1, 2, 4, 6, 15, 24, 60]
答案 45 :(得分:-1)
答案 46 :(得分:-1)
var numbers = [1,2,3,4,5,10,10, 12, 12, 6,6,6,7,8,8, 8, 8, 8 , 7 , 1 , 1, 2 , 9]
var newArr : [Int] = []
for n in numbers {
if !newArr.contains(n) {
newArr.append(n)
}
}
输出 - [1, 2, 3, 4, 5, 10, 12, 6, 7, 8, 9]
上述解决方案保持秩序,但速度很慢,因为 .contains 一次又一次地迭代。 因此使用有序集。
这将打印有序数组。
Array(NSOrderedSet.init(array: numbers))
输出 - [1, 2, 3, 4, 5, 10, 12, 6, 7, 8, 9]
这将打印一个无序数组。
let uniqueUnordered = Array(Set(numbers))
输出 - [4, 2, 1, 9, 10, 3, 5, 6, 8, 12, 7]