rubyなどの最近の言語は標準でユニークメソッドを持ってますが、なぜかswiftって地味にユニークメソッドないですよね?色々な方法があるかと思いますが、ユニークメソッドを書くことなんて最近なかったし、今回色々試したので備忘録として残しておきたいと思います。
よく見かける方法
reduce
を使ってシンプルに書く方法。要素がEquatable
を実装している必要があります。欠点としてはreduce
の上にさらにcontains
で探索するので要素が多くなると辛いかも。そんなに大きい配列を扱わない場合はこれで十分だと思います。(余談ですが、ランダムな値の配列を適当に考えるって難しくないですか?w)
let array = [1, 2, 1, 3, 4, 3, 4, 2, 5]
let result = array.reduce([], { $0.contains($1) ? $0 : $0 + [$1] })
print(result) // [1, 2, 3, 4, 5]
順番を気にしない方法
ただただ重複を排除したいだけでしたらこの方法が最も良さそう。ですが配列で値を持つからには順番を考慮したい場合が多いと思うのであまり使い道は多くなさそう?
let array = [1, 2, 1, 3, 4, 3, 4, 2, 5]
let result = Array(Set(array))
print(result) // [5, 4, 1, 2, 3]
少し速さを気にする方法
Bool
でなくても何でも良いと思います。配列の要素をキーにして辞書に既存の値をどんどん溜め込めむことで重複する値を排除する方法。この方法は要素がHashable
を実装している必要がありますね。しかしもっとカッコ良い方法ありませんかね?
let array = [1, 2, 1, 3, 4, 3, 4, 2, 5]
var dict = [Int : Bool]()
let result = array.reduce([], { (tmp, element) in
if dict[element] != nil { return tmp }
dict[element] = true
return tmp + [element]
})
print(result) // [1, 2, 3, 4, 5]
〜 2019/03/14 追記 〜
コメント欄にてSet
を使った方法を教えていただきました!
わざわざDictionary
で余計なBool
を使用しない分ムダもなくシンプルでカッコいいです!
拡張しておく
全く関係ない命名規則についてですが、破壊的な場合はsort()
、非破壊的な場合はsorted()
またはsorting()
みたいにするようですね。でもunique
って形容詞なのでunique()
で良いんでしょうか?(正直、この手の命名規則は苦手です・・・)
extension Array where Element: Hashable {
func unique() -> Array {
var hash = [Element : Bool]()
return reduce([], { (array, element) in
if hash[element] != nil { return array }
hash[element] = true
return array + [element]
})
}
}
let array = [1, 2, 1, 3, 4, 3, 4, 2, 5]
print(array.unique()) // [1, 2, 3, 4, 5]
追加の場合も考える
元の配列がユニークかつ追加する配列もユニークな場合は以下のようなメソッドを書けば良さそうです。辞書大好きですね!
extension Array where Element: Hashable {
func addUnique(array: Array) -> Array {
let dict = Dictionary(map{ ($0, 1) }, uniquingKeysWith: +)
return self + array.filter{ dict[$0] == nil }
}
}
let array1 = [1, 2, 3]
let array2 = [2, 3, 4, 1, 5]
print(array1.addUnique(array: array2)) // [1, 2, 3, 4, 5]
あとは、組み合わせれば何とかなりそうですね。
// 元の配列はユニークだけど追加する配列はユニークか分からない場合
let array1 = [1, 2, 3]
let array2 = [2, 4, 2, 5]
print(array1.addUnique(array: array2.unique()))
// 元の配列も追加する配列もユニークか分からない場合
let array3 = [1, 2, 1, 3, 2]
let array4 = [4, 3, 2, 5, 1]
print(array1.unique().addUnique(array: array2.unique())) // [1, 2, 3, 4, 5]
print((array1 + array2).unique()) // [1, 2, 3, 4, 5]
感想
ユニークなんて久しぶりに書いたのでちょっと楽しかったですw