在 Swift4 中将具有值的字典合并为数组

Merge Dictionaries With Values As Arrays in Swift4

我有三个词典,我想合并它们。请帮忙!

词典 1:

"Abc": {
    "Def": {
        "Jkl": "xxx",
    }
}

词典 2:

"Abc": {
    "Ghi": {
        "Mno": "yyy",
    }
}

词典 3:

"Abc": {
    "Ghi": {
        "Pqr": "zzz"
    }
}

我希望生成的字典将相似的值组合在一起,它应该如下所示:

"Abc": {
    "Def: {
        "Jkl": "xxx"
    },
    "Ghi": {
        "Mno": "yyy",
        "Pqr": "zzz"
    }
}

使用这个递归方法连接两个字典

func deepMerge(a: [String: Any], b: [String: Any]) -> [String: Any] {
    var result = a
    for (key, value) in b {
        //Key matches
        if let aValue = result[key] {
            //Both values are dictionaries
            if let aValDict = aValue as? [String: Any], let bValDict = value as? [String: Any] {
                result[key] = deepMerge(a: aValDict, b: bValDict)
            } else {
                //One/both values aren't dictionaries
                print("Expected two dictionaries to merge")
            }
        } else {
            //Different keys
            return a.merging(b) { (_, new) in new }
        }
    }
    return result
}

用法

let dict1 = ["Abc": ["Def": ["Jkl": "xxx"]]]
let dict2 = ["Abc": ["Ghi": ["Mno": "yyy"]]]
let dict3 = ["Abc": ["Ghi": ["Pqr": "zzz"]]]

var result = [String: Any]()
for dict in [dict1, dict2, dict3] {
    result = deepMerge(a: result, b: dict)
}
print(result)
//["Abc": ["Ghi": ["Pqr": "zzz", "Mno": "yyy"], "Def": ["Jkl": "xxx"]]]

iOSDev 解决方案是很好的且不言自明的递归函数。 我会在这里添加另一种使用 Swift 方法 merging(_:uniquingKeysWith:)

来处理字典的方法

Creates a dictionary by merging key-value pairs in a sequence into the dictionary, using a combining closure to determine the value for duplicate keys.

Swift since version 4.2

可用

您的解决方案可能看起来很自然

func mergeStandard(_ one: [String: [String: [String: String]]],
                   _ two: [String: [String: [String: String]]]) -> [String: [String: [String: String]]] {
    return one.merging(two) {
        [=10=].merging() {
            [=10=].merging() { value1, value2 -> String in
                return value1 // which is logically wrong, as we should have both values, see the Further Steps section
            }
        }
    }
}

let a = ["Abc": ["Def": ["Jkl": "xxx"]]]
let b = ["Abc": ["Ghi": ["Mno": "yyy"]]]
let c = ["Abc": ["Ghi": ["Pqr": "zzz"]]]
let d = mergeStandard(a, b)
let e = mergeStandard(d, c)

print(e)
//["Abc": ["Def": ["Jkl": "xxx"], "Ghi": ["Mno": "yyy", "Pqr": "zzz"]]]

N.B.! 当你尝试一些不同的输入时,比如

let a = ["Abc": ["Def": ["Jkl": "xxx"]]]
let b = ["Abc": ["Ghi": ["Mno": "yyy", "Pqr": "qqq"]]]
let c = ["Abc": ["Ghi": ["Pqr": "zzz"]]]

因为你有两个 "Pqr" 键。上面的代码将 select 键 "Pqr" 的值 "qqq"。另一个答案 - 来自 iOSDev 有同样的问题。请在下面查看此案例的解决方案。


进一步的步骤

我建议您将数据结构更改为 [String: [String: [String: [String]]]],这样您的最后一个值将是 StringSequence。 然后你可以使用以下内容:

func mergeUpgraded(_ one: [String: [String: [String: [String]]]],
                   _ two: [String: [String: [String: [String]]]]) -> [String: [String: [String: [String]]]] {
    return one.merging(two) {
        [=12=].merging() {
            [=12=].merging() { (arr1, arr2) -> [String] in
                var a = arr1
                var b = arr2
                a.append(contentsOf: b)
                return a
            }
        }
    }
}

let a = ["Abc": ["Def": ["Jkl": ["xxx"]]]]
let b = ["Abc": ["Ghi": ["Mno": "yyy", "Pqr": "qqq"]]]
let c = ["Abc": ["Ghi": ["Pqr": "zzz"]]]
let d = mergeUpgraded(a, b)
let e = mergeUpgraded(d, c)

print(e)
// ["Abc": ["Ghi": ["Mno": ["yyy"], "Pqr": ["qqq", "zzz"]], "Def": ["Jkl": ["xxx"]]]]

谢谢大家的帮助!这段代码对我有用:

    private 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
}