轨道
/
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,全部免费。