Menu
Coddy logo textTech

Comparable

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

Comparableは、型に<、<=、>、>=演算子を与えます。実装するのは<だけです。Swiftが残りを導出します。Comparable型はsorted()でソートでき、min()やmax()とともに使用できます:

struct Version: Comparable {
    let major: Int, minor: Int

    static func < (lhs: Version, rhs: Version) -> Bool {
        (lhs.major, lhs.minor) < (rhs.major, rhs.minor)
    }
}

let versions = [Version(major: 2, minor: 1), Version(major: 1, minor: 9), Version(major: 2, minor: 0)]
let newest = versions.max()!
print("\(newest.major).\(newest.minor)")
print(versions.sorted().map { "\($0.major).\($0.minor)" })

出力:

2.1
["1.9", "2.0", "2.1"]

タプルを比較すると、その要素が順番に比較されるため、複数のキーによる比較を短く記述できます。ここでは、まず優先度で、次に名前でタスクをソートします:

struct Task: Comparable {
    let priority: Int
    let name: String

    static func < (lhs: Task, rhs: Task) -> Bool {
        (lhs.priority, lhs.name) < (rhs.priority, rhs.name)
    }
}

let tasks = [Task(priority: 2, name: "email"), Task(priority: 1, name: "fix"), Task(priority: 2, name: "call")]
print(tasks.sorted().map { $0.name })

出力:

["fix", "call", "email"]

関連付けられた値を持たない列挙型は、< を記述しなくても Comparable に準拠できます。ケースは宣言された順序で比較されます。

enum Priority: Comparable {
    case low, medium, high
}

print(Priority.low < Priority.high)
print([Priority.high, .low, .medium].sorted())

出力:

true
[main.Priority.low, main.Priority.medium, main.Priority.high]

sorted(by:)は1回の呼び出しで任意の規則に従って並べ替えるのに対し、Comparableは型の自然な順序を定義します。この順序は、sorted()、min()、max()で常に使用されます。

struct Task: Comparable {
    let priority: Int
    let name: String
    static func < (lhs: Task, rhs: Task) -> Bool { lhs.priority < rhs.priority }
}

let tasks = [Task(priority: 3, name: "c"), Task(priority: 1, name: "a")]
print(tasks.sorted().map { $0.name })
print(tasks.sorted(by: >).map { $0.name })

出力:

["a", "c"]
["c", "a"]
challenge icon

チャレンジ

簡単

Runner(minutes、secondsとして名前とゴールタイムを持つ)をComparableに準拠させます。速いタイムを小さいものとし、同タイムの場合は名前順に並べます。sorted()でランナーをソートし、先頭3人(ランナーが3人未満の場合はその人数分)について、秒を2桁になるようにゼロ埋めした1. Ada 20:05形式の行を返すpodium(_:)を完成させてください。

提供されたコードはname,mm:ss形式の行を読み込み、返された各行を出力します。

コードはRunner.swiftとFunctions.swiftに記述してください。main.swiftには提供された入出力コードが含まれており、編集できません。

自分で試してみよう

// 提供された入出力コード: そのままにしておく
var input: [String] = []
while let line = readLine() { input.append(line) }
let runners = input.map { line -> Runner in
    let p = line.split(separator: ",").map(String.init)
    let t = p[1].split(separator: ":").map { Int($0)! }
    return Runner(name: p[0], minutes: t[0], seconds: t[1])
}
for line in podium(runners) { print(line) }
quiz icon腕試し

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

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

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