【问题标题】:How to deep merge 2 Swift dictionaries如何深度合并 2 个 Swift 词典
【发布时间】:2016-01-01 00:15:11
【问题描述】:

我的问题很简单,我想知道如何对 2 个 Swift 词典(不是 NSDictionary)进行深度合并。

let dict1 = [
    "a": 1,
    "b": 2,
    "c": [
        "d": 3
    ],
    "f": 2
]

let dict2 = [
    "b": 4,
    "c": [
        "e": 5
    ],
    "f": ["g": 6]
]

let dict3 = dict1.merge(dict2)

/* Expected:

dict3 = [
    "a": 1,
    "b": 4,
    "c": [
        "d": 3,
        "e": 5
    ],
    "f": ["g": 6]
]

*/

dict1dict2 具有相同的键时,我希望该值被替换,但如果该值是另一个字典,我希望它被递归合并。

这是我想要的解决方案:

protocol Mergeable {

    mutating func merge(obj: Self)

}

extension Dictionary: Mergeable {

    // if they have the same key, the new value is taken
    mutating func merge(dictionary: Dictionary) {
        for (key, value) in dictionary {
            let oldValue = self[key]

            if oldValue is Mergeable && value is Mergeable {
                var oldValue = oldValue as! Mergeable
                let newValue = value as! Mergeable

                oldValue.merge(newValue)

                self[key] = oldValue
            } else {
                self[key] = value
            }
        }
    }

}

但它给了我错误Protocol 'Mergeable' can only be used as a generic constraint because it has Self or associated type requirements

编辑: 我的问题与Swift: how to combine two Dictionary instances? 不同,因为那不是深度合并。

使用该解决方案,它将产生:

dict3 = [
    "a": 1,
    "b": 4,
    "c": [
        "e": 5
    ]
]

【问题讨论】:

  • 那个不是深度合并。
  • 在 Swift 中,你心目中的字典类型到底是什么?
  • 它可以是任何东西,这就是问题所在,它不一定只有 2 层深,只有字符串和数字。
  • 你不能有任何东西的 Swift 字典。请回答问题。

标签: swift dictionary


【解决方案1】:
extension Dictionary {
    mutating func deepMerge(_ dict: Dictionary) {
        merge(dict) { (current, new) in
            if var currentDict = current as? Dictionary, let newDict = new as? Dictionary {
                currentDict.deepMerge(newDict)
                return currentDict as! Value
            }
            return new
        }
    }
}

如何使用/测试:

var dict1: [String: Any] = [
    "a": 1,
    "b": 2,
    "c": [
        "d": 3
    ],
    "f": 2
]

var dict2: [String: Any] = [
    "b": 4,
    "c": [
        "e": 5
    ],
    "f": ["g": 6]
]

dict1.deepMerge(dict2)

print(dict1)

【讨论】:

  • 该示例无法正常工作。我已经测试过了。问题似乎是合并中的替换无法正常工作。尝试将 "f": 2 替换为 "f": ["g": 2] (在 dict1 中),您将不会在日志输出中收到 "f": ["g": 6] 但 "f": ["g": 2] 这是旧值(并且不正确)。我不会投反对票,但请修复它。
  • 是的,你是对的,修复并更新了答案。请核实。测试代码可以在这里找到:github.com/river2202/MonorailSwift/blob/…
【解决方案2】:

在我看来,这个问题是不连贯的。这是一个的答案,但是:

func deepMerge(d1:[String:AnyObject], _ d2:[String:AnyObject]) -> [String:AnyObject] {
    var result = [String:AnyObject]()
    for (k1,v1) in d1 {
        result[k1] = v1
    }
    for (k2,v2) in d2 {
        if v2 is [String:AnyObject], let v1 = result[k2] where v1 is [String:AnyObject] {
            result[k2] = deepMerge(v1 as! [String:AnyObject],v2 as! [String:AnyObject])
        } else {
            result[k2] = v2
        }
    }
    return result
}

这是你的测试用例:

    let dict1:[String:AnyObject] = [
        "a": 1,
        "b": 2,
        "c": [
            "d": 3
        ]
    ]

    let dict2:[String:AnyObject] = [
        "b": 4,
        "c": [
            "e": 5
        ]
    ]
    let result = deepMerge(dict1, dict2)
    NSLog("%@", result)
    /*
    {
        a = 1;
        b = 4;
        c =     {
            d = 3;
            e = 5;
        };
    }
    */

第 3 方编辑: 使用变量绑定和更新的 Swift 语法的替代版本。

func deepMerge(_ d1: [String: Any], _ d2: [String: Any]) -> [String: Any] {
    var result = d1
    for (k2, v2) in d2 {
        if let v1 = result[k2] as? [String: Any], let v2 = v2 as? [String: Any] {
            result[k2] = deepMerge(v1, v2)
        } else {
            result[k2] = v2
        }
    }
    return result
}

【讨论】:

  • 谢谢,实际上尝试了您的解决方案(我认为与我的相同)让我意识到将字典与 [String: AnyObject?] 进行比较是行不通的,我必须与 [字符串:任何对象]。还有一个问题,如何接受[String: AnyObject?]
  • 我已经说过这个问题不连贯。我回答了你问的问题。我不会在这里闲逛,而你一直在左右移动球门柱。
  • 这个问题怎么不连贯?我想要一个字典的深度合并,就像任何脚本语言一样......
  • 这个问题一点都不连贯,这是一个很好的解决方案。 :-)
【解决方案3】:

手动操作怎么样。

func += <KeyType, ValueType> (inout left: Dictionary<KeyType, ValueType>, right: Dictionary<KeyType, ValueType>) { 
    for (k, v) in right { 
        left.updateValue(v, forKey: k) 
    } 
}

你也可以试试ExSwift Library

【讨论】:

    猜你喜欢
    • 2017-02-21
    • 1970-01-01
    • 2012-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-28
    相关资源
    最近更新 更多