Edited at

【iOS】配列の要素をユニークにしてみる


初めに

今どきのiAd実装 - Qiitaを拝見いたしまして、3日目で途切れるのも嫌だったので、急遽書かせていただきます。

仕事終わりに見て次の日空いてたら極力書こうかなと思っています。

全てはiOS Second Stage Advent Calendar 2015 - Qiitaのためです。

Advent Calendarに空きを作りたくないです。


本題

何書こうか迷いましたが、今回は iOSというよりは Swiftについて書きます。

書いていいか正直迷いましたが、書いてから怒られようと思います。

ということで Swiftのジェネリックを使って配列(Array)をユニークにする方法を紹介します。

Set使えばいいじゃんっていうのは許してください。

ジェネリックやらprotocol extensionっていうのに触れてみたかったんです。


ソースコード

できるだけ Swift2の記法に合わせたくて以下の形でできました。


Uniq.swift

import Foundation

extension SequenceType where Generator.Element: Equatable {

public func uniq() -> [Generator.Element] {
var result: [Generator.Element] = []
for element in self {
if !result.contains(element) {
result.append(element)
}
}
return result
}
}

let names = ["hoge", "fuga", "foo", "bar", "fuga"].uniq()
print("names = \(names)")
// names = ["hoge", "fuga", "foo", "bar"]



解説

Arrayを拡張せずにSequenceTypeを拡張しました。

SequeceTypeについてですが、以下の記事がとってもわかりやすいので参考にしてみてください。

Swift - GeneratorとSequence - Qiita


おまけ

独自に組んだクラス(例えばAPIから取得したEntity)などで重複なしの配列に変えたい時があるかと思います。(自分がそうでしたので)

例えば以下のようなクラスを保持していたとします。


Cat.swift

class Cat {

let name: String

init(name: String) {
self.name = name
}
}


ですが同じクラス(猫)の重複を削除したい場合(上記で言えば同じ名前を持つ猫を外したい)どうしましょうという話です。

答えは簡単でCatクラスがEquatableを継承すれば大丈夫です。


Equatable

Equatableを継承すると同じ型同士を==で評価できるように実装しなければなりません。

以下のようにします。


Cat.swift

class Cat: Equatable {

let name: String

init(name: String) {
self.name = name
}
}

// これを実装します
func ==(lhs: Cat, rhs: Cat) -> Bool {
return lhs.name == rhs.name
}


上記のように実装すれば先ほど作成したuniq()関数も使えます。

またswitch文でのcaseでの分岐でも使えるので結構重宝します。


終わりに

と短めではありますが、結構これをかけるようになった時にSwiftに近づけたなって思えたので紹介しました。

最後に僕の苦悩を紹介して、終わりにします。

5分も悩んでませんでした。

以上になります。


参考