How to update a value in a nested dictionary given path fragment in Swift?

那年仲夏 提交于 2019-12-20 03:25:55

问题


I have a nested dictionary and an array containing path fragment. I need to update the value at that location.

I am possibly looking for a recursive function instead of extensions to Dictionary types and such.

I am not able to do this recursively because I making a copy of the inout param.

var dict: [String: Any] = ["channel": ["item": ["title": 1111]]]
var pathFrag = ["channel", "item", "title"]
var val = 123

func addAt(pathFrag: inout [String], val: Int, data: inout [String: Any]) {
    if let first = pathFrag.first {
        if let item = data[first] {
            print(item)
            pathFrag.remove(at: 0)
            if !pathFrag.isEmpty {
                var d: [String: Any] = data[first] as! [String: Any]
                print("e: \(d)")
                return addAt(pathFrag: &pathFrag, string: string, data: &d)
            } else {
                data[first] = val
                print("else: \(data)")  // ["title": 123]
            }
        }
    }
}


addAt(pathFrag: &pathFrag, val: val, data: &dict)
print(dict)

How to update the value of title to 123?


回答1:


Note that var d: [String: Any] = data[first] as! [String: Any] makes a copy of data[first] and not a reference to it like & and inout. So, when addAt(pathFrag: &pathFrag, string: string, data: &d) is called, only d is changed. To make this change reflect on the original data[first], you have to assign d back to data[first].

Do this:

var dict: [String: Any] = ["channel": ["item": ["title": 1111]]]
var pathFrag = ["channel", "item", "title"]

func addAt(pathFrag: inout [String], data: inout [String: Any]) {
    if let first = pathFrag.first {
        if let item = data[first] {
            pathFrag.remove(at: 0)
            if !pathFrag.isEmpty {
                var d: [String: Any] = data[first] as! [String: Any]
                addAt(pathFrag: &pathFrag, data: &d)
                data[first] = d
            } else {
                data[first] = 123
            }
        }
    }
}


addAt(pathFrag: &pathFrag, data: &dict)
print(dict)



回答2:


This is not what you asked, but the entire premise here is unSwifty. The use of [String:Any] is a Bad Smell. It seems more like Objective-C. And indeed this whole thing is a one-liner in Objective-C:

NSMutableDictionary * d1 = [[NSMutableDictionary alloc] initWithDictionary: @{ @"title" : @1111 }];
NSMutableDictionary * d2 = [[NSMutableDictionary alloc] initWithDictionary: @{ @"item" : d1 }];
NSMutableDictionary * d3 = [[NSMutableDictionary alloc] initWithDictionary: @{ @"channel" : d2 }];

Okay, that was just to prepare the data. Here’s the one-liner:

[d3 setValue:@123 forKeyPath:@"channel.item.title"];

But I would question the entire nested dictionaries concept; it seems to me you’ve gone down a wrong well here and you need to stand back and rethink your data structure.



来源:https://stackoverflow.com/questions/55198324/how-to-update-a-value-in-a-nested-dictionary-given-path-fragment-in-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!