Dictionary and Set
Collection
类型,Set
和Dictionary
并不那么最直观的。幸运的是,Swift 团队对两者做了很好的改进 [SE-0165]
Sequence Based Initialization
首先列表可以是从一系列键值对(元组)创建一个字典:
let nearestStarNames = ["Proxima Centauri", "Alpha Centauri A", "Alpha Centauri B", "Barnard's Star", "Wolf 359"]
let nearestStarDistances = [4.24, 4.37, 4.37, 5.96, 7.78]
// Dictionary from sequence of keys-values
let starDistanceDict = Dictionary(uniqueKeysWithValues: zip(nearestStarNames, nearestStarDistances))
// ["Wolf 359": 7.78, "Alpha Centauri B": 4.37, "Proxima Centauri": 4.24, "Alpha Centauri A": 4.37, "Barnard's Star": 5.96]
Duplicate Key Resolution
在初始化Dictionary
时, 你现在可以使用你喜欢的方式来处理重复的键,同时避免覆盖键值对,且不会出现任何问题:
// Random vote of people's favorite stars
let favoriteStarVotes = ["Alpha Centauri A", "Wolf 359", "Alpha Centauri A", "Barnard's Star"]
// Merging keys with closure for conflicts
let mergedKeysAndValues = Dictionary(zip(favoriteStarVotes, repeatElement(1, count: favoriteStarVotes.count)), uniquingKeysWith: +) // ["Barnard's Star": 1, "Alpha Centauri A": 2, "Wolf 359": 1]
上面的代码使用了 zip
和 +
来快捷地处理重复的 key 和冲突的值。
注意:如果你不熟悉 zip,你可以在Apple的Swift文档中快速了解它 [Swift Documentation]
Filtering
Dictionary 和 Set
现在都可以将结果 通过filter函数 过滤到原始类型的新对象中:
// Filtering results into dictionary rather than array of tuples
let closeStars = starDistanceDict.filter { $0.value < 5.0 }
closeStars // Dictionary: ["Proxima Centauri": 4.24, "Alpha Centauri A": 4.37, "Alpha Centauri B": 4.37]
Dictionary Mapping
Dictionary
为直接映射其值提供了一种非常有用的方法::
// Mapping values directly resulting in a dictionary
let mappedCloseStars = closeStars.mapValues { "\($0)" }
mappedCloseStars // ["Proxima Centauri": "4.24", "Alpha Centauri A": "4.37", "Alpha Centauri B": "4.37"]
Dictionary Default Values
在Dictionary上访问某个值时,常见的做法是使用nil-coalescing operator
给出默认值(译者注: 不了解nil-coalescing operator 的伙伴 可参见Nil-Coalescing Operator。Dictionary Default Values
可以更简洁:
// Subscript with a default value
let siriusDistance = mappedCloseStars["Wolf 359", default: "unknown"] // "unknown"
// Subscript with a default value used for mutating
var starWordsCount: [String: Int] = [:]
for starName in nearestStarNames {
let numWords = starName.split(separator: " ").count
starWordsCount[starName, default: 0] += numWords // Amazing
}
starWordsCount // ["Wolf 359": 2, "Alpha Centauri B": 3, "Proxima Centauri": 2, "Alpha Centauri A": 3, "Barnard's Star": 2]
swift4之前, 处理这种情况需要包装在臃肿的if - let
语句中。现在简短的代码即可.
Dictionary Grouping
另一个令人惊讶称赞的是,我们可以从Sequence
"中初始化Dictionary
,并将其分组为bucket::
// Grouping sequences by computed key
let starsByFirstLetter = Dictionary(grouping: nearestStarNames) { $0.first! }
// ["B": ["Barnard's Star"], "A": ["Alpha Centauri A", "Alpha Centauri B"], "W": ["Wolf 359"], "P": ["Proxima Centauri"]]