繁体   English   中英

快速将字典数组中的键值替换为嵌套字典

[英]Swift replace key value in array of dictionaries with nested dictionaries

我有快速字典[String:Any],它以数组[[String:Any]]的形式存储在UserDefauls中

我想做的是将key:值替换为另一个,例如"id": "x:coredataid""id": "server id"

我需要先遍历数组,然后遍历所有键值。 为此有什么优雅的解决方案吗?

如果不是,那么如何简单地遍历字典中的所有键值和所有嵌套级别?

我有此代码: for (key, value) in params

但这仅适用于顶级密钥。

让我详细解释一下。 如您所见,我有phases键,它是一个数组。 同样,每个phase包含day键,该键也是一个数组。

因此,我实际上并不关心键的命名,将其分阶段还是几天,是否想要迭代所有键,提供的[String:Any]字典中的值并检查键是否包含等于提供的字符串的值。

如您所见,当前executionId等于: <x-coredata://C3C82F5A-8709-4EDC-8AE5-C23C65F220D5/WorkoutEntity/t072831FB-8F5C-4589-85CB-6D084671C097815>我用红线下划线。

在此处输入图片说明

所以我想循环字典以捕获这个关键的ExerciseId,并检查是否等于<x-coredata://C3C82F5A-8709-4EDC-8AE5-C23C65F220D5/WorkoutEntity/t072831FB-8F5C-4589-85CB-6D084671C097815>

再有一次我不在乎workoutId名称,实际上可以将键命名为exerciseId或id。 我只想在我的整个字典中找到一个值<x-coredata://C3C82F5A-8709-4EDC-8AE5-C23C65F220D5/WorkoutEntity/t072831FB-8F5C-4589-85CB-6D084671C097815> ,如果有很多替换所有的他们。

我需要它的原因是连接到我存储的标识符的区域设置,该区域等于您注意到的CoreData标识符。 但是,当我用从服务器返回的新标识符修改CoreData记录时,我想用新ID替换我的UserDefaults离线请求存储。

我还对此代码进行了修改:

func update(_ dict: [String: Any], set serverId: Any, for localId: String) -> [String: Any] {
        var newDict = dict
        for (k, v) in newDict {
            if let mobileLocalId = v as? String {
                if mobileLocalId == localId {
                    newDict[k] = serverId
                } else { newDict[k] = v }
            } else if let subDict = v as? [String: Any] {
                newDict[k] = update(subDict, set: serverId, for: localId)
            } else if let dictionaries = v as? [[String: Any]] {
                for dictionary in dictionaries {
                    newDict[k] = update(dictionary, set: serverId, for: localId)
                }
            }
        }
        return newDict
    }

但是它对我和newDict的下落天看起来像这样:

(lldb) po newDict
▿ 2 elements
  ▿ 0 : 2 elements
    - key : "position"
    - value : 0
  ▿ 1 : 2 elements
    - key : "workoutId"
    - value : "5d51723b3faceb53f9d2d5ed"

我确实在这里成功地更改了标识符,但是现在忽略了上面示例中的所有其他键对。

此递归函数将遍历所有键值:

func iterateThroughAllKeyValues<Key: Hashable, Value>(of dictionary: Dictionary<Key, Value>, execute execution: ((Key, Value))->()) {
    for element in dictionary {
        if let dictionary = element.value as? [Key: Value] {
            iterateThroughAllKeyValues(of: dictionary, execute: execution)
        } else {
            execution(element)
        }
    }
}

您也可以进行一点点更改就可以在任何嵌套字典的主节点上execution调用。

这是扩展模式:

extension Dictionary {
    func iterateThroughAllKeyValues(execute execution: ((Key, Value))->()) {
        for element in self {
            if let dictionary = element.value as? [Key: Value] {
                dictionary.iterateThroughAllKeyValues(execute: execution)
            } else {
                execution(element)
            }
        }
    }
}

注意 :请谨慎订购

用法示例:

let dictionary: [String: Any] = [
    "id0": "value0",
    "nested": ["id1": "value1"],
    "nestedNested": ["id2": "value2",
                     "nested": ["id3": "value3"]]
]

dictionary.iterateThroughAllKeyValues { (key, value) in
    print("key:", key, "Value:", value)
}

输出:

键:id0值:value0

键:id1值:value1

键:id3值:value3

键:id2值:value2

这是一个具有递归函数的解决方案,该函数替换给定键的所有值。

func update(_ dict: [String: Any], set value: Any, for key: String) -> [String: Any] {
    var newDict = dict
    for (k, v) in newDict {
        if k == key {
            newDict[k] = value
        } else if let subDict = v as? [String: Any] {
            newDict[k] = update(subDict, set: value, for: key)
        } else if let subArray = v as? [[String: Any]] {
            var newArray = [[String: Any]]()
            for item in subArray {
                newArray.append(update(item, set: value, for: key))
            }
            newDict[k] = newArray
        }
    }
    return newDict
}

请注意,它不会检查现有值是哪种类型,而是直接将其替换为新值。 代码还假定嵌套数组的唯一类型是字典数组。

对于数组,此功能可以与map一起使用

let out = data.map { update($0, set: "newValue", for: "id")}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM