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

时间:2019-08-11 20:10:53

标签: swift dictionary

我有一个快速的字典[String:Any],我将它存储在UserDefauls中作为数组[[String:Any]]

我想做的是用另一个替换键:value,例如"id": "x:coredataid""id": "server id"

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

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

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

但这仅适用于顶级密钥。

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

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

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

enter image description here

所以我想循环字典以捕获此关键的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>,如果有很多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 } ,请全部替换。

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

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

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

但是对于我和newDict来说,它却以某种方式下降了几天:

context.startForegroundService(serviceIntent);
mainThreadHdlr = hdlr;

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

2 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:1)

这是一个具有递归功能的解决方案,该功能可以替换给定键的所有值。

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")}