Inspiriert von https://www.swiftbysundell.com/posts/the-power-of-key-paths-in-swift können wir ein leistungsfähigeres Tool deklarieren, das auf jedem keyPath nach Einheitlichkeit filtern kann. Dank der Kommentare von Alexander zu verschiedenen Antworten bezüglich der Komplexität sollten die folgenden Lösungen nahezu optimal sein.
Nicht mutierende Lösung
Wir erweitern mit einer Funktion, die in der Lage ist, auf jedem keyPath nach Einigkeit zu filtern:
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 }
}
}
Hinweis: Wenn Ihr Objekt nicht RangeReplaceableCollection, sondern Sequence entspricht, können Sie diese zusätzliche Erweiterung verwenden. Der Rückgabetyp ist jedoch immer ein Array:
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 }
}
}
Verwendung
Wenn wir wie in der Frage eine Einheit für die Elemente selbst wünschen, verwenden wir den 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] */
Wenn wir Einheit für etwas anderes wollen (wie für die id
eine Sammlung von Objekten), verwenden wir den Schlüsselpfad unserer Wahl:
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}] */
Mutierende Lösung
Wir erweitern mit einer Mutationsfunktion, die in der Lage ist, auf jedem keyPath nach Einigkeit zu filtern:
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 }
}
}
Verwendung
Wenn wir wie in der Frage eine Einheit für die Elemente selbst wünschen, verwenden wir den 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] */
Wenn wir die Einheitlichkeit für etwas anderes wollen (wie für id
eine Sammlung von Objekten), verwenden wir den Schlüsselpfad unserer Wahl:
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 zu konvertieren. NSSet ist eine ungeordnete Sammlung von Objekten, wenn die Reihenfolge NSOrderedSet beibehalten werden muss.