从Swift中删除数组中的重复元素

时间:2014-09-09 07:21:59

标签: arrays swift standard-library

我可能有一个如下所示的数组:

[1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]

或者,实际上,任何类似数据类型的序列。我想要做的是确保每个相同的元素只有一个。例如,上面的数组将成为:

[1, 4, 2, 6, 24, 15, 60]

请注意,删除了重复的2,6和15,以确保每个相同的元素只有一个。斯威夫特是否提供了一种方便的方法,或者我必须自己做这件事吗?

47 个答案:

答案 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)

swift 2

使用 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解决方案,用于从阵列中删除重复项。该解决方案改进了以下提出的许多其他解决方案:

  • 保留输入数组中元素的顺序
  • 线性复杂度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]

此代码利用insertSet操作返回的结果,该操作在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)

Swift 4.2已测试

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() )。注释掉的代码演示了扩展检查的相等性,其中someOtherEquatablePropertyEquatable类型的另一个属性(但也可以是返回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)

Xcode 10.1- Swift 4.2简单而强大的解决方案

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)

  1. 首先将数组的所有元素添加到NSOrderedSet。
  2. 这将删除阵列中的所有重复项。
  3. 再次将此有序集转换为数组。

完成。...

示例

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)

  1. 转换为设置
  2. 检查元素计数是否等于
  3. 之前的数组
  4. 如果否,则从Set
  5. 创建数组

答案 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]