タプルと型推論
読了目安 約3分
値の組をタプルで束ねる。辞書順の比較と組み合わせて、多キーのソートを一行で書く。
この章の目次
「名前と点数」「x 座標と y 座標」のような値の組は、競プロのあらゆる場面に現れます。 組をそのまま 1 つの値として運ぶ道具がタプルです。
タプルを作る・分解する
タプルは、複数の値を括弧で束ねた値です。
let point = (3, 5)
print(point.0, point.1)
let (x, y) = point
print(x + y)中身は .0 .1 で取り出せます。
let (x, y) = point と書くと、まとめて別々の定数に分解できます。
型は書かなくても、中身から (Int, Int) と型推論されます。
配列と違って、(1, "alice") のように違う型も混ぜられます。
ラベル付きタプル
要素に名前を付けると、番号より読み間違えにくくなります。
let user = (name: "alice", score: 90)
print(user.name, user.score)関数から複数の値を返す
戻り値の型をタプルにすると、関数が複数の値を一度に返せます。
func minMax(_ a: [Int]) -> (min: Int, max: Int) {
return (a.min()!, a.max()!)
}
let r = minMax([3, 1, 4, 1, 5])
print(r.min, r.max)a.min()! の ! は「配列が空ではない」とみなす印です。
タプルの比較
同じ型どうしのタプルは < で比較できます。
先頭の要素から比べ、等しければ次の要素で決まります。
この順序を辞書順と呼びます。
print((1, 5) < (2, 3))
print((2, 5) < (2, 3))
print(("alice", 90) < ("alice", 95))2 番目の値でソート
sorted { 条件 } と書くと、並び順を自分で決められます。
$0 と $1 に比較される 2 つの要素が入り、true を返すと $0 が前に並びます。
この書き方の仕組みは クロージャと高階関数 で扱います。
let items = [("alice", 90), ("bob", 80), ("carol", 90)]
let ranking = items.sorted { ($0.1, $0.0) < ($1.1, $1.0) }
for item in ranking {
print(item.0, item.1)
}試してみよう: bob の点数を 95 に変えて、末尾に移ることを確かめてください。
多キーソートの定石は、比較したいキーを優先順にタプルへ並べることです。 上の例は「点数の昇順、同点なら名前の昇順」になります。
降順にしたいキーは、符号を反転して並べます。
// 点数の降順、同点なら名前の昇順
let ranking = items.sorted { (-$0.1, $0.0) < (-$1.1, $1.0) }学びどころ
| 概念 | 一言まとめ |
|---|---|
| タプル | 複数の値を括弧で束ねた値。違う型も混ぜられる |
| ラベル付きタプル | (name: "alice", score: 90) で名前アクセス |
| 多値返却 | 戻り値の型をタプルにする |
| 辞書順の比較 | 先頭の要素から順に比べる |
| 多キーソート | 比較キーをタプルに並べる。降順は符号を反転 |
演習
1 行目に人数 N が入力されます。 続く N 行に、名前 S と点数 P が空白区切りで入力されます。
点数の降順に、同点の場合は名前の昇順に並べ替え、「名前 点数」を 1 行ずつ出力してください。
制約: 1 ≤ N ≤ 100。名前は英小文字のみで、全員異なります。0 ≤ P ≤ 100。
入力例:
4
carol 70
alice 90
dave 90
bob 80
出力例:
alice 90
dave 90
bob 80
carol 70模範解答
let n = Int(readLine()!)!
var people: [(name: String, score: Int)] = []
for _ in 0..<n {
let parts = readLine()!.split(separator: " ")
people.append((name: String(parts[0]), score: Int(parts[1])!))
}
let ranking = people.sorted { (-$0.score, $0.name) < (-$1.score, $1.name) }
for p in ranking {
print(p.name, p.score)
}点数の符号を反転したタプルを比べると、「点数の降順、同点なら名前の昇順」になります。