如其他答案中已经解释的那样,
Value
类型必须被限制为
Hashable
,否则它不能成为新字典的
Key
。
此外,还需要决定如何处理源字典中的重复值。
对于实现,可以将源字典映射到一个键和值互换的序列中,并将其传递给以下初始化程序之一:
这两种方法在处理重复键时有所不同:第一种会中止并抛出运行时异常,第二种会调用闭包以解决冲突。
因此,一个简单的实现方式是:
extension Dictionary where Value: Hashable {
func swapKeyValues() -> [Value : Key] {
return Dictionary<Value, Key>(uniqueKeysWithValues: lazy.map { ($0.value, $0.key) })
}
}
采用惰性映射源字典的方式,避免创建一个包含所有交换键/值元组的中间数组。
示例:
let dict = [1 : "a", 2 : "b", 3 : "c", 4 : "d", 5 : "e"]
print(dict.swapKeyValues()) //["b": 2, "e": 5, "a": 1, "d": 4, "c": 3]
如果源字典中有重复的值,这将崩溃。以下是一种变体,可以接受源字典中的重复值(后来的值会覆盖早期的值):
extension Dictionary where Value: Hashable {
func swapKeyValues() -> [Value : Key] {
return Dictionary<Value, Key>(lazy.map { ($0.value, $0.key) }, uniquingKeysWith: { $1 })
}
}
例子:
let dict = [1 : "a", 2 : "b", 3 : "b"]
print(dict.swapKeyValues()) // ["b": 3, "a": 1]
另一个选项是将其实现为字典初始化器。例如:
extension Dictionary where Value: Hashable {
init?(swappingKeysAndValues dict: [Value: Key]) {
self.init(uniqueKeysWithValues: dict.lazy.map( { ($0.value, $0.key) }))
}
}
如果源字典中存在重复的值,该函数将会崩溃,
或者作为一个抛出初始化程序
extension Dictionary where Value: Hashable {
struct DuplicateValuesError: Error, LocalizedError {
var errorDescription: String? {
return "duplicate value"
}
}
init(swappingKeysAndValues dict: [Value: Key]) throws {
try self.init(dict.lazy.map { ($0.value, $0.key) },
uniquingKeysWith: { _,_ in throw DuplicateValuesError() })
}
}
或者作为可失败的初始化器:
extension Dictionary where Value: Hashable {
struct DuplicateValuesError: Error { }
init?(swappingKeysAndValues dict: [Value: Key]) {
do {
try self.init(dict.lazy.map { ($0.value, $0.key) },
uniquingKeysWith: { _,_ in throw DuplicateValuesError() })
} catch {
return nil
}
}
}
示例(用于可失败的初始化程序):
let dict = [1 : "a", 2 : "b", 3 : "c", 4 : "d", 5 : "e"]
if let newDict = Dictionary(swappingKeysAndValues: dict) {
print(newDict)
}
或者,如果您确信不存在重复的值:
let dict = [1 : "a", 2 : "b", 3 : "c", 4 : "d", 5 : "e"]
let newDict = Dictionary(swappingKeysAndValues: dict)!