Inspiré par https://www.swiftbysundell.com/posts/the-power-of-key-paths-in-swift , nous pouvons déclarer un outil plus puissant capable de filtrer pour l'unicité sur n'importe quel chemin de clé. Grâce aux commentaires d'Alexander sur diverses réponses concernant la complexité, les solutions ci-dessous devraient être presque optimales.
Solution non mutante
Nous étendons avec une fonction qui est capable de filtrer l'unicité sur n'importe quel keyPath:
extension RangeReplaceableCollection {
/// Returns a collection 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>) -> Self {
var unique = Set<T>()
return filter { unique.insert($0[keyPath: keyPath]).inserted }
}
}
Remarque: dans le cas où votre objet n'est pas conforme à RangeReplaceableCollection, mais est conforme à Sequence, vous pouvez avoir cette extension supplémentaire, mais le type de retour sera toujours un tableau:
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 le 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 id
une collection d'objets) alors 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 qui est capable de filtrer pour l'unicité sur n'importe quel 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 le 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 id
une collection d'objets) alors 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}] */
NSSet
, NSSet est une collection d'objets non ordonnée, si nécessaire pour maintenir l'ordre NSOrderedSet.