LoginSignup
2
1

More than 5 years have passed since last update.

配列の要素の重複をチェックする

Last updated at Posted at 2017-11-24

配列の要素の重複を汎用的にチェックする

配列の要素の重複をチェックしたく以下の extension を実装してみた。

extension Array {
    func hasDuplicatedElements(where predicate: @escaping (Self.Element, Self.Element) throws -> Bool) rethrows -> Bool {
        var checkedOffsets: [Int: [Int]] = [:]
        for lhs in self.enumerated() {
            checkedOffsets[lhs.offset] = [lhs.offset]
            for rhs in self.enumerated() {
                let checked = checkedOffsets[rhs.offset]?.contains(rhs.offset) ?? false
                guard !checked else { continue }
                if try predicate(lhs.element, rhs.element) { return true }
                checkedOffsets[lhs.offset]!.append(rhs.offset)
            }
        }
        return false
    }
}

こんな model と配列があったとして、

struct Model {
    let id: String
}

let models = [Model(id: "x"), Model(id: "x")]

こんな感じで使える。ElementEquatable に準拠してなくても使える。

models.hasDuplicatedElements { (lhs, rhs) -> Bool in lhs.id == rhs.id } // true

すでに確認した要素同士の比較を避けているので、 for 文の回る回数は最大で 要素数の二乗 / 2 となるはず。
汎用的に書いたのでどこでも使えるぞ〜ってことで一旦満足した。

結局上のコードは捨てた

現状で配列の重複チェックなんて特定のモデル以外で書かないし、汎用的に書くことを諦めれば for 文の回る回数も最大で配列の要素数となるので、使うモデルクラスのみに extension を生やしてそれを使うことにした。

extension Array where Self.Element == Model {
    func hasDuplicatedElements() -> Bool {
        var ids = Set<String>()
        for model in self {
            if ids.contains(model.id) { return true }
            ids.insert(model.id)
        }
        return false
    }
}
2
1
0

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
2
1