Help us understand the problem. What is going on with this article?

swiftで配列のユニーク

More than 1 year has passed since last update.

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

shou8
色々勉強してきたことを備忘録として書き残しておこうと思います。誰かのためになればとても良いことですが、もはや誰かのためにならなくても自分のためになれば良いですw 生温かい目で見守ってもらえると幸いです!
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした