我想创建一个函数,它将Dictionary
并返回所述字典,但其值为键,其键为各自的值。到目前为止,我已经做了一个功能,但我不能为我的生活使extension
成为Dictionary
。
func swapKeyValues<T, U>(of dict: [T : U]) -> [U : T] {
let arrKeys = Array(dict.keys)
let arrValues = Array(dict.values)
var newDict = [U : T]()
for (i,n) in arrValues.enumerated() {
newDict[n] = arrKeys[i]
}
return newDict
}
let dict = [1 : "a", 2 : "b", 3 : "c", 4 : "d", 5 : "e"]
let newDict = swapKeyValues(of: dict)
print(newDict) //["b": 2, "e": 5, "a": 1, "d": 4, "c": 3]
let dict = [1 : "a", 2 : "b", 3 : "c", 4 : "d", 5 : "e"]
//I would like the function in the extension to be called swapped()
print(dict.swapped()) //["b": 2, "e": 5, "a": 1, "d": 4, "c": 3]
我如何实现这一理想?
答案 0 :(得分:4)
Dictionary的扩展名可能如下所示,成为键的value
必须限制为Hashable
extension Dictionary where Value : Hashable {
func swapKeyValues() -> [Value : Key] {
assert(Set(self.values).count == self.keys.count, "Values must be unique")
var newDict = [Value : Key]()
for (key, value) in self {
newDict[value] = key
}
return newDict
}
}
let dict = [1 : "a", 2 : "b", 3 : "c", 4 : "d", 5 : "e"]
let newDict = dict.swapKeyValues()
print(newDict)
答案 1 :(得分:3)
正如其他答案中已经解释的那样,Value
类型必须是
限制为Hashable
,否则不能为Key
新词典。
还必须决定源字典中的重复值 应该处理。
对于实现,可以将源字典映射到a 序列与键和值交换,并传递给 其中一个初始化者
这些不同之处在于如何处理重复键:第一个中止 运行时异常,第二个调用闭包 冲突解决。
所以一个简单的实现是
extension Dictionary where Value: Hashable {
func swapKeyValues() -> [Value : Key] {
return Dictionary<Value, Key>(uniqueKeysWithValues: lazy.map { ($0.value, $0.key) })
}
}
(映射源词典 lazily 避免创建 具有所有交换键/值元组的中间数组。)
示例:的
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) //["b": 2, "e": 5, "a": 1, "d": 4, "c": 3]
}
或者,如果您确定不会出现重复值:
let dict = [1 : "a", 2 : "b", 3 : "c", 4 : "d", 5 : "e"]
let newDict = Dictionary(swappingKeysAndValues: dict)!
答案 2 :(得分:2)
要清楚,除非值符合Hashable
协议,否则您所要求的内容是不可能的。因此,条件扩展是您正在寻找的。 p>
extension Dictionary where Value: Hashable {
func keyValueSwapped() -> [Value:Key] {
var newDict = [Value:Key]()
keys.forEach { (key) in
let value = self[key]!
newDict[value] = key
}
return newDict
}
}
答案 3 :(得分:0)
您可以映射字典以交换键和值,并使用Dictionary(uniqueKeysWithValues:)
初始化程序创建一个新字典:
let dict = ["Key1": "Value1", "Key2": "Value2", ...]
let swappedDict = Dictionary(uniqueKeysWithValues: dict.map {(key, value) in return (value, key)})
只需考虑Value
类型应符合Hashable协议,并且在键重复的情况下,初始化程序会抛出运行时异常。如果原始字典可能具有重复的值,请改用Dictionary(_:uniquingKeysWith:)
初始化程序。