學習軌道
/
Swift
Swift
/
練習
/
高分排行榜
高分排行榜

高分排行榜

學習練習

簡介

字典是 Swift 的主要集合型別之一。 字典以無序的方式儲存唯一的鍵與對應值之間的關聯。 字典中所有的鍵都必須是相同的型別,所有的值也必須共用相同的型別。

字典字面值寫成以逗號分隔的 key: value 配對,並用方括號括起來:

var addresses: Dictionary<String, String> = [
    "The Munsters": "1313 Mockingbird Lane",
    "The Simpsons": "742 Evergreen Terrace",
    "Buffy Summers": "1630 Revello Drive"
]

var sequences: [String: [Int]] = [
    "Euler's totient": [1, 1, 2, 2, 4, 2, 6, 4],
    "Lazy caterer": [1, 2, 4, 7, 11, 16, 22, 29, 37],
    "Carmichael": [561, 1105, 1729, 2465, 2821, 6601, 8911, 10585, 15841]
]

let constants = [
    "pi": 3.14159,
    "e": 2.71828,
    "phi": 1.618033,
    "avogadro": 6.02214076e23
]

字典型別可以用兩種方式明確寫出:Dictionary<Key, Value>,或是簡寫語法[Key: Value]。

要建立空字典,必須明確指定它的鍵與值型別:

var emptyDict1: [Int: Int] = [:]
var emptyDict2 = [Character: String]()
var emptyDict3 = Dictionary<Int, Double>()

存取值

你可以用下標表示法來存取值:把鍵放在字典名稱後面的方括號裡。 由於某個鍵可能不存在於字典中,下標存取會回傳一個可選值(Value?)。 如果鍵存在,Swift 會回傳包裝後的值;如果不存在,則回傳nil:

let munster: String? = addresses["The Munsters"]
// Returns Optional("1313 Mockingbird Lane")

let carmichael = sequences["Carmichael"]
// Returns Optional([561, 1105, 1729, 2465, 2821, 6601, 8911, 10585, 15841])

let planck = constants["planck"]
// Returns nil

為了避免處理可選值,你可以用default參數提供預設值:

let e: Double = constants["e", default: 0]
// Returns 2.71828

let hoagie: [Int] = sequences["Hoagie", default: []]
// Returns []

let betty = addresses["Betty Cooper", default: "Address unknown"]
// Returns "Address unknown"

修改字典

對於用var宣告的可變字典,你可以用下標賦值來新增或更新鍵值對:

sequences["Euler's totient"]?.append(contentsOf: [6, 4])
// sequences["Euler's totient"] is now [1, 1, 2, 2, 4, 2, 6, 4, 6, 4]

addresses["Betty Cooper"] = "111 Queens Ave."
addresses["Betty Cooper", default: "Address unknown"]
// Returns "111 Queens Ave."

constants["Gelfond's"] = 23.140692
// Compiler error: Cannot assign through subscript: 'constants' is a 'let' constant

疊代字典

你可以用for-in迴圈疊代字典中的每一個鍵值對。 每個項目都會以(key, value)元組的形式提供:

for (name, address) in addresses {
    print("\(name) lives at \(address)")
}

排序字典

由於字典是無序的,排序後會產生一個由鍵值對組成的陣列。 你可以傳入一個閉包給sorted(by:)方法,這個閉包會比較兩個(key, value)元組,並在第一個元組應該排在第二個之前時回傳true:

func sortByNameLengthThenValue(_ lhs: (key: String, value: Double), _ rhs: (key: String, value: Double)) -> Bool {
    let left = lhs.value + Double(lhs.key.count)
    let right = rhs.value + Double(rhs.key.count)
    return left < right
}

let sortedConstants = constants.sorted(by: sortByNameLengthThenValue)

說明

在這個練習中,你要實作一種記錄高分的方式,用來追蹤你當地遊樂場裡最熱門遊戲的高分。

你要實作 7 個函式,全都和回傳及操作高分資料的字典有關。

1. 定義一個新的高分字典

建立一個不接受任何參數的函式newScoreBoard(),它會回傳一個新的高分字典,這個字典的鍵是型別為String的值,而值則是型別為Int的值。

2. 將玩家加入高分字典

若要將玩家加入高分字典,請定義addPlayer(_:_:_:),這是一個接收 3 個參數的函式:

  • 第一個參數是分數的字典。 這應該是一個輸入輸出參數。
  • 第二個參數是玩家名稱,以字串表示。
  • 第三個參數是分數,以整數表示。 這個參數是選用的,請把第三個參數的預設值設為 0。
var highScores = newScoreBoard()
addPlayer(&highScores, "Dave Thomas")
// Returns ["Dave Thomas": 0]
addPlayer(&highScores, "José Valim", 486_373)
// Returns ["Dave Thomas": 0, "José Valim": 486_373]

3. 從分數字典中移除玩家

若要從高分字典中移除玩家,請定義removePlayer(_:_:),它接收 2 個參數:

  • 第一個參數是分數的字典。 這應該是一個輸入輸出參數。
  • 第二個參數是玩家名稱,以字串表示。

如果玩家在字典裡,這個函式應該將他從字典中移除;否則就什麼都不做。

var highScores = ["Dave Thomas": 0, "José Valim": 486_373]
removePlayer(&highScores, "Dave Thomas")
// Returns ["José Valim": 486_373]
removePlayer(&highScores, "Rose Fanaras")
// Returns ["José Valim": 486_373]

4. 重設玩家的分數

若要重設玩家的分數,請定義resetPlayer(_:_:),它接收 2 個參數:

  • 第一個參數是分數的字典。 這應該是一個輸入輸出參數。
  • 第二個參數是玩家名稱,以字串表示,也就是你想重設分數的玩家。

這個函式會將該玩家的分數設為 0。 如果玩家不在字典裡,就什麼都不做。

var highScores = ["Dave Thomas": 486_373, "José Valim": 10]
resetScore(&highScores, "Dave Thomas")
// Returns ["Dave Thomas": 0, "José Valim": 10]

5. 更新玩家的分數

若要透過加上先前的分數來更新玩家分數,請定義updateScore,它接收 3 個參數:

  • 第一個參數是分數的字典。這應該是一個輸入輸出參數。
  • 第二個參數是玩家名稱,以字串表示,也就是你想更新分數的玩家。
  • 第三個參數是你想加到已儲存高分上的分數。
var highScores = ["Dave Thomas": 0, "José Valim": 486_373]
addPlayer(&highScores, "Freyja Ćirić", 12_771_008)
updateScore(&highScores, "Freyja Ćirić", 73)
// Returns ["Dave Thomas": 0, "José Valim": 486_373, "Freyja Ćirić": 12_771_081]

6. 取得依玩家名稱排序的玩家與分數清單

定義函式orderByPlayers,它接收 1 個參數:

  • 第一個參數是分數的字典。

這個函式會回傳一個由(String, Int)元組組成的陣列,內容是玩家和他們的高分,並依玩家名稱遞增排序。

var highScores = ["Dave Thomas": 0, "José Valim": 486_373, "Freyja Ćirić": 12_771_091]
orderByPlayers(highScores)
// Returns [("Dave Thomas", 0), ("Freyja Ćirić", 12_771_091), ("José Valim", 486_373)]

7. 取得依玩家分數遞減排序的玩家清單

若要取得依分數遞減排序的玩家清單,請定義orderByScores,它接收 1 個參數:

  • 第一個參數是分數的字典。

這個函式會回傳一個由(String, Int)元組組成的陣列,內容是玩家和他們的高分,並依玩家分數遞減排序。

var highScores = ["Dave Thomas": 0, "José Valim": 486_373, "Freyja Ćirić": 12_771_091]
orderByScores(highScores)
// Returns [("Freyja Ćirić", 12_771_091), ("José Valim", 486_373), ("Dave Thomas", 0)]
透過 GitHub 編輯 連結會在新視窗或分頁中開啟
Swift Exercism

準備好開始 高分排行榜 了嗎?

註冊 Exercism,透過 35 個概念116 個練習 和真人引導來學習並精通 Swift,全部免費。