Удаление дублирующихся элементов из массива в Swift - программирование

Удаление дублирующихся элементов из массива в Swift

У меня может быть массив, который выглядит следующим образом:

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

Или, действительно, любая последовательность типизированных частей данных. То, что я хочу сделать, это убедиться, что есть только один из каждого идентичного элемента. Например, приведенный выше массив станет следующим:

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

Обратите внимание, что дубликаты из 2, 6 и 15 были удалены, чтобы убедиться, что существует только один из каждого идентичного элемента. Сможет ли Свифт сделать это легко, или я должен сам это сделать?

4b9b3361

Ответ 1

Вы можете свернуть свои собственные, например, как это (обновлено для Swift 1.2 с Set):

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
}

И как расширение для Array:

extension Array where Element: Hashable {
    var uniques: Array {
        var buffer = Array()
        var added = Set<Element>()
        for elem in self {
            if !added.contains(elem) {
                buffer.append(elem)
                added.insert(elem)
            }
        }
        return buffer
    }
}

Ответ 2

Вы можете легко конвертировать в набор и обратно в массив:

let unique = Array(Set(originals))

Это не гарантирует сохранение исходного порядка массива.

Ответ 3

Многие ответы доступны здесь, но я пропустил это простое расширение, подходящее для 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 }

Ответ 4

Это берет некоторую полезную информацию, которая уже есть на этой странице, и применяет подход Hashable/Set, когда это возможно, и в противном случае возвращается к уравнительному коду.

Swift 4 изменений для Equatable расширения (Hashable остается неизменным)

public extension Sequence where Element: Equatable {
  var uniqueElements: [Element] {
    return self.reduce(into: []) {
      uniqueElements, element in

      if !uniqueElements.contains(element) {
        uniqueElements.append(element)
      }
    }
  }
}

Свифт 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]
    }
  }
}

Ответ 5

Swift 3.0

let uniqueUnordered = Array(Set(array))
let uniqueOrdered = Array(NSOrderedSet(array: array))

Ответ 6

редактировать/обновлять 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 нажмите здесь

Ответ 7

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). Смотрите документацию.

Использование возвращаемого значения помогает нам избежать зацикливания или выполнения каких-либо других операций.

Ответ 8

Swift 4

Гарантированно сохранить порядок.

extension Array where Element: Equatable {
    func removingDuplicates() -> Array {
        return reduce(into: []) { result, element in
            if !result.contains(element) {
                result.append(element)
            }
        }
    }
}

Ответ 9

Здесь категория по SequenceType, которая сохраняет первоначальный порядок массива, но использует Set сделать contains Lookups, чтобы избежать O(n) стоимость на массив 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 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

Отсюда альтернативное (если не оптимальное) решение с использованием неизменяемых типов, а не переменных:

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
}

Включено противопоставление Жана-Пилиппе императивного подхода с функциональным подходом.

В качестве бонуса эта функция работает как со строками, так и с массивами!

Изменить: Этот ответ был написан в 2014 году для Swift 1.0 (до того, как Set был доступен в Swift). Он не требует соответствия Hashable и работает в квадратичном времени.

Ответ 11

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

Ответ 12

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()

Ответ 13

Еще одно решение 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]

Код расширения Array:

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

Вы можете напрямую использовать коллекцию наборов для удаления дубликата, а затем вернуть его в массив

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]

Ответ 15

Вдохновленные https://www.swiftbysundell.com/posts/the-power-of-key-paths-in-swift, мы можем объявить более мощный инструмент, способный фильтровать уникальность для любого keyPath. Благодаря комментариям Александра к различным ответам относительно сложности, приведенные ниже решения должны быть почти оптимальными.

Не мутирующее решение

Мы расширяем функцию, которая может фильтровать уникальность для любого 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

Для массивов, где элементы не являются ни Hashable, ни Comparable (например, сложные объекты, словари или структуры), это расширение предоставляет обобщенный способ удаления дубликатов:

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, и это позволяет вам использовать различные комбинации полей для уникальности.

Примечание: для более надежного подхода см. Решение, предложенное Coeur, в комментариях ниже.

fooobar.com/questions/49156/...

[Редактировать] Swift 4 альтернатива

С Swift 4.2 вы можете использовать класс Hasher для создания хешей. Вышеупомянутое расширение может быть изменено, чтобы использовать это:

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}     
    }
}

Синтаксис вызова немного отличается, потому что замыкание получает дополнительный параметр, содержащий функцию для хэширования переменного числа значений (которое должно быть по отдельности Hashable)

peopleArray = peopleArray.filterDuplicate{ $0($1.name, $1.age, $1.sex) } 

Он также будет работать с одним значением уникальности (используя $ 1 и игнорируя $ 0).

peopleArray = peopleArray.filterDuplicate{ $1.name } 

Ответ 17

Если вам нужны отсортированные значения, это работает (Swift 4)

let sortedValues = Array(Set(array)).sorted()

Ответ 18

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 }
    }
}

Ответ 19

Немного более сжатая версия синтаксиса Даниэль Кром Свифт 2 ответ, используя закрывающее закрытие и сокращенное имя аргумента, которое, по-видимому, основано на Первоначальный ответ скорости воздушной скорости:

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 extends 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

Ответ 20

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)

Ответ 21

Вы всегда можете использовать словарь, потому что словарь может содержать только уникальные значения. Например:

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"]

.

Ответ 22

здесь я сделал некоторое 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")

Ответ 23

Я использовал ответ @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) })
  }
}

Ответ 24

Это просто очень простая и удобная реализация. Вычисленное свойство в расширении массива, имеющего эквивалентные элементы.

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
    }
}

Ответ 25

  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

вывод массива без дубликатов - [1,2,4,6,8]

Ответ 26

Вот ответ, который я придумал после поиска в Интернете и не находил того, что искал. Используя Set, вы можете добавить все элементы с уменьшением. Затем я беру результат и преобразовываю его в отсортированный массив.

let initialArray = [1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]

let distinct2 = initialArray.reduce(Set<Int>(), combine: { (set, current) -> Set<Int> in
    var tmp = set
    tmp.insert(current)
    return tmp
})

// distinct2 is now a set containing {2, 4, 60, 6, 15, 24, 1}

// Make it into a sorted array
let sorted = Array(distinct2).sorted(<) // Returns [1, 2, 4, 6, 15, 24, 60]

Ответ 27

Swift 3

На основе ответа Jean-Philippe Pellet, я обновил его синтаксис для Swift 3.

func uniq<S : Sequence, T : Hashable where S.Iterator.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(source: vals) // [1, 4, 2, 6, 24, 15, 60]

Ответ 28

Позвольте мне предложить ответ, похожий на ответ Скотта Гарднера, но с более лаконичным синтаксисом с использованием сокращения. Это решение удаляет дубликаты из массива пользовательских объектов (сохраняя начальный порядок)

// 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 и поиграть.

Ответ 29

В 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
    }
}

Ответ 30

Для этого я сделал простое расширение.

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() чтобы 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]