Swift: сгладить массив словарей в один словарь

в Swift, я пытаюсь сгладить массив словарей в одном словаре я.е

let arrayOfDictionaries = [["key1": "value1"], ["key2": "value2"], ["key3": "value3", "key4": "value4"]]


//the end result will be:   
 flattenedArray = ["key1": "value1", "key2": "value2", "key3": "value3", "key4": "value4"]

Я попытался использовать flatmap, но тип возвращаемого результата [(String, AnyObject)], а не [String, Object] ie

let flattenedArray = arrayOfDictionaries.flatMap {  }
// type is [(String, AnyObject)]

Итак, у меня есть 2 вопроса:

  • Почему возвращается тип [(String, AnyObject)]? И что означают скобки?

  • как мне достичь желаемого результата?

Edit: я бы предпочитайте использовать функциональный подход с картой Swift / flatmap/reduce и т. д. вместо for-loop

4 ответов


что означают скобки?

это, наряду с запятой вместо двоеточия, должно дать первый ключ: скобки означают, что вы получаете массив кортежей. Поскольку вы ищете словарь, а не массив, это говорит вам, что вам нужно преобразовать последовательность кортежей (пар ключ-значение) в один словарь.

как мне достичь желаемого результата?

один из способов сделать это будет использовать reduce, как это:

let flattenedDictionary = arrayOfDictionaries
    .flatMap {  }
    .reduce([String:String]()) { (var dict, tuple) in
        dict.updateValue(tuple.1, forKey: tuple.0)
        return dict
    }

С Swift 4, Dictionay есть init(_:uniquingKeysWith:) инициализатор. init(_:uniquingKeysWith:) есть следующее объявление:

init<S>(_ keysAndValues: S, uniquingKeysWith combine: (Value, Value) throws -> Value) rethrows where S : Sequence, S.Element == (Key, Value)

создает новый словарь из пар ключ-значение в данной последовательности, используя объединение закрытия, чтобы определить значение для любых дубликатов ключей.


два следующих фрагмента кода Playground показывают, как сгладить массив словарей в новый словарь.

let dictionaryArray = [["key1": "value1"], ["key1": "value5", "key2": "value2"], ["key3": "value3"]]

let tupleArray: [(String, String)] = dictionaryArray.flatMap {  }
let dictonary = Dictionary(tupleArray, uniquingKeysWith: { (first, last) in last })

print(dictonary) // prints ["key2": "value2", "key3": "value3", "key1": "value5"]
let dictionaryArray = [["key1": 10], ["key1": 10, "key2": 2], ["key3": 3]]

let tupleArray: [(String, Int)] = dictionaryArray.flatMap {  }
let dictonary = Dictionary(tupleArray, uniquingKeysWith: { (first, last) in first + last })
//let dictonary = Dictionary(tupleArray, uniquingKeysWith: +) // also works

print(dictonary) // ["key2": 2, "key3": 3, "key1": 20]

обновление ответа @dasblinkenlight для Swift 3.

" var " в параметрах был устаревшим, но этот подход отлично работал для меня.

let flattenedDictionary = arrayOfDictionaries
    .flatMap {  }
    .reduce([String:String]()) { (dict, tuple) in
        var nextDict = dict
        nextDict.updateValue(tuple.1, forKey: tuple.0)
        return nextDict
    }

вот как это сделать

let arrayOfDictionaries = [["key1": "value1"], ["key2": "value2"], ["key3": "value3", "key4": "value4"]]
var dic = [String: String]()
for item in arrayOfDictionaries {
    for (kind, value) in item {
        print(kind)
        dic.updateValue(value, forKey: kind)
    }


}
print(dic)

print(dic["key1"]!)

выход

OUTPUT