Menu
Coddy logo textTech

Hashable

CoddyのSwiftジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 40/57。

Hashable により、値を Set に格納したり、Dictionary のキーとして使用したりできます。ハッシュとは、値から計算される数値であり、その値をすばやく見つけるために使用されます。すべてのプロパティが Hashable である構造体や列挙型は、適合を宣言することでこれを取得できます。

struct Point: Hashable {
    let x: Int, y: Int
}

var visited: Set<Point> = []
visited.insert(Point(x: 0, y: 0))
visited.insert(Point(x: 1, y: 0))
visited.insert(Point(x: 0, y: 0))
print(visited.count)
print(visited.contains(Point(x: 1, y: 0)))

出力:

2
true

ハッシュ可能な値は、構造化された値の出現回数を数える場合など、辞書のキーとして適しています。

struct Pair: Hashable {
    let from: String, to: String
}

let trips = [Pair(from: "A", to: "B"), Pair(from: "B", to: "C"), Pair(from: "A", to: "B")]
var counts: [Pair: Int] = [:]
for t in trips { counts[t, default: 0] += 1 }
print(counts[Pair(from: "A", to: "B")]!)

出力:

2

Hashable は Equatable を基盤としています。== が一部のプロパティのみを比較する場合、ハッシュでも同じプロパティを使用する必要があり、それは hash(into:) で行います。そうしないと、等しい2つの値が異なるハッシュを持つ可能性があり、集合が両方を保持してしまいます。

struct User: Hashable {
    let id: Int
    var name: String

    static func == (lhs: User, rhs: User) -> Bool { lhs.id == rhs.id }
    func hash(into hasher: inout Hasher) { hasher.combine(id) }
}

let users: Set<User> = [User(id: 1, name: "Ada"), User(id: 1, name: "Ada L."), User(id: 2, name: "Bo")]
print(users.count)

出力:

2

覚えておくべきルール:等しい値は等しいハッシュ値を持たなければなりません。ハッシュ値はプログラムの実行ごとに変化するため、保存したり出力したりしてはいけません。セットや辞書を介してのみ使用してください。

// 等しい値 -> 等しいハッシュ(必須)
// 異なる値 -> 通常は異なるハッシュ
func hash(into hasher: inout Hasher) {
    hasher.combine(id)          // == が比較するプロパティとまったく同じ
}
challenge icon

チャレンジ

簡単

グリッド上のロボットが、(0, 0) から一度に1ステップずつ U、D、L、R に移動します。Position (x, y) を Hashable にし、3行を返す explore(_:) を完成させてください。返す3行は、visited 5 cells(開始位置を含む異なる位置の数)、revisits 2(すでに訪問したセルに着地した移動の数)、most visited (0, 0) x3(開始位置を1回の訪問として数え、最も多く入ったセル。同数の場合は、その回数に最初に到達したセルを選ぶ)です。

用意されたコードは移動を1行読み取り、返された各行を出力します。

コードは Position.swift と Functions.swift に記述します。main.swift には用意された入力/出力コードが含まれており、編集できません。

自分で試してみよう

// 提供された入出力コード: そのままにしておく
var input: [String] = []
while let line = readLine() { input.append(line) }
for line in explore(input[0]) { print(line) }
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Swiftプレイグラウンド