web-dev-qa-db-fra.com

Supprimer des éléments en double d'un tableau dans Swift

Je pourrais avoir un tableau qui ressemble à ce qui suit:

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

Notez que les doublons de 2, 6 et 15 ont été supprimés pour garantir qu’il n’y avait qu’un élément de chaque élément identique. Swift fournit-il un moyen de le faire facilement ou devrai-je le faire moi-même?

178
Altair357

Vous pouvez rouler le vôtre, par exemple comme ceci ( mis à jour pour Swift 1.2 avec 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 version:

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

Vous pouvez facilement convertir en un ensemble et revenir à un tableau:

let unique = Array(Set(originals))

Cela ne garantit pas le maintien de l'ordre d'origine du tableau.

379
Ben Packard

Beaucoup de réponses disponibles ici, mais j'ai raté cette extension simple, adaptée à Swift 2 et plus:

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

C'est très simple. Peut être appelé comme ça:

let arrayOfInts = [2, 2, 4, 4]
print(arrayOfInts.removeDuplicates()) // Prints: [2, 4]

Filtrage basé sur les propriétés

Pour filtrer un tableau en fonction de propriétés, vous pouvez utiliser cette méthode:

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

Que vous pouvez appeler comme suit:

let filteredElements = myElements.filterDuplicates { $0.PropertyOne == $1.PropertyOne && $0.PropertyTwo == $1.PropertyTwo }
57
Antoine

Cela prend quelques-unes des bonnes informations déjà sur cette page, et applique l'approche si possible Hashable/Set, et revient au code Equatable sinon.

Swift 4 change pour l'extension Equatable (Hashable reste identique)

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]
    }
  }
}
51
Jessy

Swift 3.0

let uniqueUnordered = Array(Set(array))
let uniqueOrdered = Array(NSOrderedSet(array: array))
43
Jovan Stankovic

Contraindre les éléments de la collection à Equatable, vous pouvez utiliser contient: 

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

Une autre option consiste à contraindre l'élément de collection à Hashable et à utiliser un ensemble pour contrôler les éléments à mapper dans le résultat:

extension Collection where Element: Hashable {
    var orderedSet: [Element]  {
        var set = Set<Element>()
        return compactMap { set.insert($0).inserted ? $0 : nil }
    }
}

en utilisant un filtre:

extension Collection where Element: Hashable {
    var orderedSet: [Element]  {
        var set = Set<Element>()
        return filter { set.insert($0).inserted }
    }
}

ou en utilisant NSOrderedSet:

extension Array where Element: Hashable {
    var orderedSet: Array {
        return NSOrderedSet(array: self).array as? Array ?? []
    }
}

En utilisant Swift 4 réduire (en :)

extension Collection where Element: Hashable {
    var orderedSet: [Element] {
        var set: Set<Element> = []
        return reduce(into: []) { set.insert($1).inserted ? $0.append($1) : () }
    }
}

let integers = [1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]
let integersOrderedSet = integers.orderedSet // [1, 4, 2, 6, 24, 15, 60]

Vous pouvez également étendre le protocole RangeReplaceableCollection pour lui permettre d'être également utilisé avec les types StringProtocol (Strings et SubStrings):

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"

Méthode de mutation

var string = "abcdefabcghi"
string.removeDuplicates() 
string  //  "abcdefghi"

var substring = "abcdefabcdefghi".dropFirst(3)  // "defabcdefghi"
substring.removeDuplicates()
substring   // "defabcghi"
33
Leo Dabus

Swift 4

Garanti pour continuer à commander.

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

Swift 4

public extension Array where Element: Hashable {
    func uniqued() -> [Element] {
        var seen = Set<Element>()
        return filter{ seen.insert($0).inserted }
    }
}

chaque tentative de insert renverra également un Tuple: (inserted: Bool, memberAfterInsert: Set.Element). Voir documentation

L'utilisation de la valeur renvoyée nous évite d'avoir à boucler ou à effectuer une autre opération. 

22
mxcl

Une solution alternative (sinon optimale) de ici utilisant des types immuables plutôt que des variables:

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
}

Inclus pour opposer l'approche impérative de Jean-Pillippe à une approche fonctionnelle.

En prime, cette fonction fonctionne aussi bien avec des chaînes que des tableaux!

Edit: Cette réponse a été écrite en 2014 pour Swift 1.0 (avant que Set soit disponible dans Swift). Il ne nécessite pas de conformité Hashable et s'exécute en temps quadratique.

11
Pliskin

Swift 2

avecuniqfunction réponse:

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

utilisation:

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
10
Daniel Krom

Voici une catégorie sur SequenceType qui conserve l'ordre d'origine du tableau, mais utilise un Set pour effectuer les recherches contains afin d'éviter le coût O(n) avec la méthode contains(_:) du tableau.

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

ou si vous n'avez pas Hashable, vous pouvez faire ceci:

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

Vous pouvez les coller dans votre application. Swift choisira la bonne en fonction du type Iterator.Element de votre séquence.

10
deanWombourne

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

usage:

["Ljubljana", "London", "Los Angeles", "Ljubljana"].unique()

ou

["Ljubljana", "London", "Los Angeles", "Ljubljana"].uniqueOrdered()
7
Rok Gregorič

Une autre solution Swift 3.0 pour supprimer les doublons d’un tableau. Cette solution améliore de nombreuses autres solutions déjà proposées par:

  • Préserver l'ordre des éléments dans le tableau d'entrée
  • Complexité linéaire O (n): filtre passe unique O(n) + ensemble d'insertion O (1)

Étant donné le tableau entier:

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]

Code fonctionnel:

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]

Code d'extension du tableau: 

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]

Ce code tire parti du résultat renvoyé par l'opération insert sur Set qui s'exécute sur O(1) et renvoie un tuple indiquant si l'élément a été inséré ou s'il existait déjà dans l'ensemble.

Si l'élément était dans l'ensemble, filter l'exclura du résultat final.

6
Eneko Alonso

Vous pouvez utiliser directement une collection de jeux pour supprimer les doublons, puis les reconvertir en tableau

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]

Ensuite, vous pouvez commander votre tableau comme vous le souhaitez

myArray.sort{$0 < $1} // [1, 2, 4, 6, 15, 24, 60]
6

Inspiré par https://www.swiftbysundell.com/posts/the-power-of-key-paths-in-Swift , nous pouvons déclarer un outil plus puissant qui peut filtrer l’unicité de n’importe quel chemin keyPath. Grâce aux commentaires d'Alexander sur diverses réponses concernant la complexité, les solutions ci-dessous devraient être quasi optimales.

Solution non mutante

Nous étendons avec une fonction qui est capable de filtrer l'unicité sur n'importe quel 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 }
    }
}

Usage

Si nous voulons l’unicité pour les éléments eux-mêmes, comme dans la question, nous utilisons 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] */

Si nous voulons l’unicité pour autre chose (comme pour la id d’une collection d’objets), nous utilisons le chemin de clé de notre choix:

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}] */

Solution de mutation

Nous étendons avec une fonction de mutation capable de filtrer l’unicité sur n’importe quel chemin 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 }
    }
}

Usage

Si nous voulons l’unicité pour les éléments eux-mêmes, comme dans la question, nous utilisons 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] */

Si nous voulons l’unicité pour autre chose (comme pour la id d’une collection d’objets), nous utilisons le chemin de clé de notre choix:

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}] */
5
Cœur

Swift 4.2 Testé

extension Sequence where Iterator.Element: Hashable {
    func unique() -> [Iterator.Element] {
        var seen: [Iterator.Element: Bool] = [:]
        return self.filter { seen.updateValue(true, forKey: $0) == nil }
    }
}
4
blackjacx

Version syntaxique légèrement plus succincte de Daniel Krom's Swift 2 answer , utilisant un nom de clôture et d'argument, qui semble reposer sur la réponse originale de 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 }
}

Exemple d'implémentation d'un type personnalisé pouvant être utilisé avec uniq(_:) (qui doit être conforme à Hashable, et donc Equatable, car Hashable s'étend 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
  }

}

Dans le code ci-dessus ...

id, tel qu’utilisé dans la surcharge de ==, peut être n’importe quel type Equatable (ou une méthode renvoyant un type Equatable, par exemple, someMethodThatReturnsAnEquatableType()). Le code de commentaire commente l'extension du contrôle d'égalité, où someOtherEquatableProperty est une autre propriété d'un type Equatable (mais peut également être une méthode renvoyant un type Equatable).

id, telle qu'utilisée dans la propriété calculée hashValue (requise pour se conformer à Hashable), peut être toute propriété Hashable (et donc Equatable) (ou méthode renvoyant un type Hashable).

Exemple d'utilisation de 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
3
Scott Gardner

Pour les tableaux où les éléments ne sont ni Hashable ni Comparable (par exemple, objets complexes, dictionnaires ou structures), cette extension fournit un moyen généralisé de supprimer les doublons:

extension Array
{
   func filterDuplicate<T>(_ keyValue:(Element)->T) -> [Element]
   {
      var uniqueKeys = Set<String>()
      return filter{uniqueKeys.insert("\(keyValue($0))").inserted}
   }
}

// example usage: (for a unique combination of attributes):

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

Vous n'avez pas à vous soucier de rendre les valeurs Hashable et cela vous permet d'utiliser différentes combinaisons de champs pour plus d'unicité.

3
Alain T.
func removeDublicate (ab: [Int]) -> [Int] {
var answer1:[Int] = []
for i in ab {
    if !answer1.contains(i) {
        answer1.append(i)
    }}
return answer1
}

Usage:

let f = removeDublicate(ab: [1,2,2])
print(f)
3
Jack Rus

ici, j'ai fait quelques O(n) solutions pour les objets. Pas une solution de quelques lignes, mais ...

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")
2
kas-kad

Vous pouvez toujours utiliser un dictionnaire, car un dictionnaire ne peut contenir que des valeurs uniques. Par exemple:

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

Comme vous pouvez le constater, le tableau résultant ne sera pas toujours "en ordre". Si vous souhaitez trier/ordonner le tableau, ajoutez ceci:

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

.

2
AT3D

Permettez-moi de suggérer une réponse semblable à celle de Réponse de Scott Gardner mais avec une syntaxe plus laconique en utilisant reduction . Cette solution supprime les doublons d'un tableau d'objets personnalisés (en conservant l'ordre initial)

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

Et juste si vous vous demandez comment cela fonctionne: la magie de réduction est la même, mais la syntaxe de réduction est plus étendue.

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

Vous pouvez simplement copier-coller ce code dans une aire de jeu Swift et jouer.

2
n0_quarter

J'ai utilisé la réponse de @ Jean-Philippe Pellet pour créer une extension Array qui effectue des opérations sur les tableaux, tout en conservant l'ordre des éléments.

/// 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) })
  }
}
2
Will Richardson
  1. Ajoutez d’abord tous les éléments d’un tableau à NSOrderedSet.
  2. Cela supprimera tous les doublons de votre tableau.
  3. Convertissez à nouveau ce jeu ordonné en un tableau.

Terminé....

Exemple

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

sortie de arrayWithoutDuplicates - [1,2,4,6,8]

2
Mahendra Thotakura

Je pense qu’il serait bon d’offrir une fonction uniq() et uniqInPlace() pour muter un tableau en supprimant ses valeurs. Cela fonctionne comme les fonctions sort() et sortInPlace() fournies par Swift. De plus, puisqu'il s'agit d'un tableau, il devrait conserver l'ordre d'origine des éléments.

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

Vous ne pouvez utiliser que uniqInPlace() sur un tableau Array variable (c.-à-d. var), car vous ne pouvez pas muter un tableau constant (c.-à-d. let).

Quelques exemples d'utilisation:

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

Ceci est juste une implémentation très simple et pratique. Une propriété calculée dans une extension d'un tableau contenant des éléments équivalents. 

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

c’est le moyen le plus simple dans Swift 4.2 et suivant le code ci-dessous

let keyarray:NSMutableArray = NSMutableArray()

for  object in dataArr
{
    if !keysArray.contains(object){
        keysArray.add(object)
    }
}

print(keysArray)
1
Deepak Yadeedya

Dans Swift 3.0, la solution la plus simple et la plus rapide que j'ai trouvée pour éliminer les éléments dupliqués tout en respectant l'ordre:

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
    }
}
1
Ciprian Rarau

J'ai fait une extension aussi simple que possible à cette fin.

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

Vous pouvez utiliser duplicatesRemoved() pour obtenir un nouveau tableau, dont les éléments en double sont supprimés, ou removeDuplicates() pour se muter. Voir:

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]
1
Igor Silva

Le moyen le plus simple serait d'utiliser NSOrderedSet, qui stocke des éléments uniques et préserve l'ordre des éléments. Comme:

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)
0
sgl0v

Préservez les valeurs uniques et préservez le tri dans un tableau. 

(en utilisant 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]
0
oOEric

Pensez comme un programmeur fonctionnel :)

Pour filtrer la liste en fonction de la présence ou non de l'élément, vous avez besoin de l'index. Vous pouvez utiliser enumerated pour obtenir l'index et map pour revenir à la liste de valeurs.

let unique = myArray
    .enumerated()
    .filter{ myArray.firstIndex(of: $0.1) == $0.0 }
    .map{ $0.1 }

Cela garantit la commande. Si l'ordre ne vous dérange pas, la réponse existante de Array(Set(myArray)) est plus simple et probablement plus efficace.

0
Tim MB

Ma solution, il semble que cela puisse être en O(n), car l'accès à la carte de hachage est O (1) et le filtre est O (n). Il utilise également par fermeture pour sélectionner la propriété permettant de distinguer les éléments les uns après les autres.

extension Sequence {

    func distinct<T: Hashable>(by: (Element) -> T) -> [Element] {
        var seen: [T: Bool] = [:]
        return self.filter { seen.updateValue(true, forKey: by($0)) == nil }
    }
}
0
Michał Ziobro

Voici un moyen plus flexible de rendre une séquence unique avec une fonction de correspondance personnalisée.

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

XCode 10.1 - Swift 4.2 Une solution simple et puissante

func removeDuplicates(_ nums: inout [Int]) -> Int {
    nums = Set(nums).sorted()
    return nums.count
}

Exemple

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]
0
Saranjith

Cela fonctionne dans Swift 4, si vous ne voulez pas/n'avez pas besoin de convertir le résultat en tableau, mais pouvez le faire avec un ensemble. Le résultat n'est pas trié par défaut, mais vous pouvez le faire avec trié (), qui renvoie un tableau, comme indiqué dans l'instruction 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]
0
Johannes

J'ai créé une fonction d'ordre supérieur dont la complexité temporelle est o (n). En outre, une fonctionnalité telle que la carte permet de renvoyer le type de votre choix.

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