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"]チャレンジ
簡単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) }
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Swiftプレイグラウンド