配列の要素の重複を汎用的にチェックする
配列の要素の重複をチェックしたく以下の 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")]
こんな感じで使える。Element
が Equatable
に準拠してなくても使える。
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
}
}