https://www.swiftbysundell.com/posts/the-power-of-key-paths-in-swiftに触発されて、任意のkeyPathの単一性をフィルタリングできるより強力なツールを宣言できます。複雑さに関するさまざまな回答についてのAlexanderコメントのおかげで、以下の解決策はほぼ最適になるはずです。
非変異ソリューション
任意の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 }
}
}
注:オブジェクトがRangeReplaceableCollectionに準拠しているが、Sequenceには準拠している場合、この追加の拡張機能を使用できますが、戻り値の型は常に配列になります。
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}] */
NSSet
。NSSetは、順序NSOrderedSetを維持する必要がある場合、オブジェクトの順序なしコレクションです。