Как обновить значение во вложенном словаре по заданному фрагменту пути в Swift? - PullRequest
2 голосов
/ 16 марта 2019

У меня есть вложенный словарь и массив, содержащий фрагмент пути. Мне нужно обновить значение в этом месте.

Возможно, я ищу рекурсивную функцию вместо расширений для Dictionary типов и тому подобное.

Я не могу сделать это рекурсивно, потому что я делаю копию параметра inout.

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)

Как обновить значение title до 123?

Ответы [ 2 ]

3 голосов
/ 16 марта 2019

Обратите внимание, что var d: [String: Any] = data[first] as! [String: Any] делает копию data[first], а не ссылку на нее, как & и inout. Таким образом, когда вызывается addAt(pathFrag: &pathFrag, string: string, data: &d), изменяется только d. Чтобы это изменение отразилось на исходном data[first], вам необходимо присвоить d обратно data[first].

Сделайте это:

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 голосов
/ 16 марта 2019

Это не то, что вы просили, но вся посылка здесь неповторима. Использование [String:Any] - плохой запах. Это больше похоже на Objective-C. И действительно, в Objective-C вся эта штука однострочная:

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

Хорошо, это было только для подготовки данных. Вот одна строка:

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

Но я бы поставил под сомнение всю концепцию вложенных словарей; мне кажется, что вы ошиблись здесь, и вам нужно отступить и пересмотреть свою структуру данных.

...