交换键和字典扩展价值观 - Swift 4.1

时间:2018-04-24 16:41:05

标签: swift function dictionary swap swift-extensions

字典扩展 - 交换字典键&值

Swift 4.1,Xcode 9.3

我想创建一个函数,它将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]

我如何实现这一理想?

4 个答案:

答案 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协议,否则您所要求的内容是不可能的。因此,条件扩展是您正在寻找的。

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:)初始化程序。