LoginSignup
24
27

More than 5 years have passed since last update.

swiftで配列のユニーク

Last updated at Posted at 2019-03-12

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

24
27
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
27