Arrayの差分確認、シンプルなので個人の癖が出る。

開発環境

> xcodebuild -version
Xcode 13.0
Build version 13A233

前提

struct CustomStruct {
    let name: String
}

var a1: [CustomStruct] = stride(from: 0, to: 1000, by: 1).compactMap {
    return .init(name: $0.description)
}

var a2: [CustomStruct] = stride(from: 0, to: 1000, by: 1).compactMap {
    return .init(name: $0.description)
}

var a3: [CustomStruct] = stride(from: 0, to: 2000, by: 2).compactMap {
    return .init(name: $0.description)
}

ユーザー定義の構造体を要素に持つArrayの差分確認を行う。
Arrayともう一方のArrayに含まれる要素が完全に一致するか確認できればOK。
単純比較(O(N^2)) などあるが、今回はSwiftライクに書いてみる。

1. Equatable を準拠させて比較

struct CustomStruct: Equatable {
    let name: String
}

...

print(a1 == a2)  // true
print(a2 == a3) // false

構造体に Equatable を準拠させて比較。
かなりシンプルに書ける。これで十分。

2. Hashable を準拠させてハッシュ値を生成し比較

struct CustomStruct: Hashable {
    let name: String
}

... 

var hasher1 = Hasher()
hasher1.combine(a1)
hasher1.finalize() // 6303833638181181639

var hasher2 = Hasher()
hasher2.combine(a2)
hasher2.finalize() // 6303833638181181639

var hasher3 = Hasher()
hasher3.combine(a3)
hasher3.finalize() // -7034783640522885626

 

Never call finalize() on hasher. Doing so may become a compile-time error in the future.
hash(into:) | Apple Developer Documentation

finalize() は将来的にコンパイルエラーになるかもしれないとのこと。

 

Finalizing consumes the hasher: it is illegal to finalize a hasher you don’t own, or to perform operations on a finalized hasher. (These may become compile-time errors in the future.)
finalize() | Apple Developer Documentation

所有していない Hasher を finalize() することは違法らしい。想定しない、が日本語的にしっくりきそう。

あくまで将来の話で、現時点ではコンパイルエラーにならない。

 

また、ハッシュ値は複数環境下で等しいことが保証されないので、UserDefaults に保存して将来的に再利用することは意味を持たない。

3. Hashable を準拠させてSetに入れて比較

struct CustomStruct: Hashable {
    let name: String
}

...

let set1 = Set(a1.compactMap {$0})
let set2 = Set(a2.compactMap {$0})
let set3 = Set(a3.compactMap {$0})

print(set1 == set2)  // true
print(set2 == set3)  // false

この記事を書くまではこれが真っ先に思いついていた。
1の方がシンプルなのでこれからは1を使っていく。

参考