how dictionaries declarar create arreglo array swift declarative

swift - dictionaries - ¿Hay una manera declarativa de transformar Array a Dictionary?



string array in swift 3 (8)

Buenas respuestas ya. Aquí hay una forma adicional con una extensión de tipo de colección. Puede convertir cualquier tipo de colección a un diccionario, matriz o conjunto.

extension CollectionType { func map2Dict<K, V>(@noescape map: ((Self.Generator.Element) -> (K, V)?)) -> [K: V] { var d = [K: V]() for e in self { if let kV = map(e) { d[kV.0] = kV.1 } } return d } func map2Array<T>(@noescape map: ((Self.Generator.Element) -> (T)?)) -> [T] { var a = [T]() for e in self { if let o = map(e) { a.append(o) } } return a } func map2Set<T>(@noescape map: ((Self.Generator.Element) -> (T)?)) -> Set<T> { return Set(map2Array(map)) } }

Aquí está el ejemplo de uso.

let entries = ["x=5", "y=7", "z=10"] let dict:[String: String] = entries.map2Dict({ let components = $0.componentsSeparatedByString("=") return (components.first!, components.last!) }) print("dict /(dict)")

Quiero obtener de esta serie de cadenas

let entries = ["x=5", "y=7", "z=10"]

a esto

let keyValuePairs = ["x" : "5", "y" : "7", "z" : "10"]

Intenté usar el map pero el problema parece ser que un par clave-valor en un diccionario no es un tipo distinto, solo está en mi mente, pero no en el tipo de Diccionario, así que realmente no podría proporcionar una función de transformación porque no existe. no es nada para transformarse. Además, el map devuelve una matriz, por lo que es un no ir.

¿Algunas ideas?


Manera simple:

let array = ["key1", "key2", "key3"] let dict = array.flatMap({["/($0)" : "value"]})

Salida:

[(clave: "clave1", valor: "valor"), (clave: "clave2", valor: "valor"), (clave: "clave3", valor: "valor")]

Una forma un poco más compleja:

let array = ["key1", "key2", "key3"] let dict = array.enumerated().flatMap({["/($0.element)" : "value/($0.offset)"]})

Salida:

[(clave: "clave1", valor: "valor0"), (clave: "clave2", valor: "valor1"), (clave: "clave3", valor: "valor2")]


Me gusta la respuesta de @paulgriffiths, pero si tiene una aversión extrema a los errores de tiempo de ejecución, puede dar un paso más para asegurarse de que cada cadena de la matriz inicial tenga ambos elementos necesarios ...

La diferencia importante en este código en comparación con los otros es que verifico para asegurar que realmente haya un "=" en la cadena con elementos en ambos lados. El flatMap filtra efectivamente cualquier que falle.

extension Dictionary { func withUpdate(key: Key, value: Value) -> Dictionary<Key, Value> { var result = self result[key] = value return result } } let entries = ["x=5", "y=7", "z=10"] let keyValues = entries.flatMap { str -> (String, String)? in let split = str.characters.split("=").map(String.init) return split.count > 1 ? (split[0], split[1]) : nil } let keyValuePairs = keyValues.reduce([String: String]()) { $0.withUpdate($1.0, value: $1.1) }


Si tiene dos arreglos paralelos, puede usar zip() , Array() y la extensión del Diccionario de David Berry :

let numbers = [10, 9, 8] let strings = ["one", "two", "three", "four"] let dictionary = Dictionary(elements: Array(zip(numbers, strings))) // == [10: "one", 9: "two", 8: "three"]

No olvides añadir la extensión:

extension Dictionary { init(elements:[(Key, Value)]) { self.init() for (key, value) in elements { updateValue(value, forKey: key) } } }


Una forma de hacerlo es en dos etapas con map y reduce con una tupla como valor intermedio, por ejemplo:

let entries = ["x=5", "y=7", "z=10"] let dict = entries.map { (str) -> (String, String) in let elements = str.characters.split("=").map(String.init) return (elements[0], elements[1]) }.reduce([String:String]()) { (var dict, kvpair) in dict[kvpair.0] = kvpair.1 return dict } for key in dict.keys { print("Value for key ''/(key)'' is /(dict[key]).") }

salidas:

Value for key ''y'' is Optional("7"). Value for key ''x'' is Optional("5"). Value for key ''z'' is Optional("10").

o con una sola reduce con la misma salida:

let entries = ["x=5", "y=7", "z=10"] let dict = entries.reduce([String:String]()) { (var dict, entry) in let elements = entry.characters.split("=").map(String.init) dict[elements[0]] = elements[1] return dict } for key in dict.keys { print("Value for key ''/(key)'' is /(dict[key]).") }


Utilice el nuevo método de reduce(into: Result) Swift 4 reduce(into: Result) :

let keyValuePairs = entries.reduce(into: [String:String]()) { (dict, entry) in let key = String(entry.first!) let value = String(entry.last!) dict[entry.first!] = entry.last! }

Por supuesto, la división de su String podría mejorarse.


Y para todos los demás que disfrutan de sobrecargas y de una sola línea.

public func +<K, V>(lhs: [K:V], rhs: [K:V]) -> [K:V] { var lhs: [K:V] = lhs for (key, value) in rhs { lhs[key] = value } return lhs } let array = ["x=5", "y=7", "z=10"] let dictionary = array.map({ $0.componentsSeparatedByString("=") }).reduce([:]) { $0 + [$1[0]: $1[1]] } print(dictionary) // ["y": "7", "x": "5", "z": "10"]


Swift 4

Como se menciona en fl034, esto se puede simplificar en algunos casos con Swift 4, donde una versión de error comprobado se ve así:

let foo = entries .map { $0.components(separatedBy: "=") } .reduce(into: [String:Int64]()) { dict, pair in if pair.count == 2, let value = Int64(pair[1]) { dict[pair[0]] = value } }

Aún más simple si no quieres los valores como Ints:

let foo = entries .map { $0.components(separatedBy: "=") } .reduce(into: [String:String]()) { dict, pair in if pair.count == 2 { dict[pair[0]] = pair[1] } }

Mayor TL; DR

Comprobación de errores menos, se parece bastante a:

let foo = entries.map({ $0.componentsSeparatedByString("=") }) .reduce([String:Int]()) { acc, comps in var ret = acc ret[comps[0]] = Int(comps[1]) return ret }

Usa el mapa para convertir la [String] en una división [[String]] y luego crea el diccionario de [String:Int] partir de eso usando reducir.

O, agregando una extensión al Dictionary :

extension Dictionary { init(elements:[(Key, Value)]) { self.init() for (key, value) in elements { updateValue(value, forKey: key) } } }

(Bastante una extensión útil por cierto, puede usarla para muchas operaciones de mapa / filtro en los diccionarios, realmente es una pena que no exista por defecto)

Se vuelve aún más simple:

let dict = Dictionary(elements: entries .map({ $0.componentsSeparatedByString("=") }) .map({ ($0[0], Int($0[1])!)}) )

Por supuesto, también puede combinar las dos llamadas de mapa, pero prefiero dividir las transformaciones individuales.

Si desea agregar alguna comprobación de errores, puede usar flatMap lugar del map :

let dict2 = [String:Int](elements: entries .map({ $0.componentsSeparatedByString("=") }) .flatMap({ if $0.count == 2, let value = Int($0[1]) { return ($0[0], value) } else { return nil }}) )

Nuevamente, si lo desea, obviamente puede combinar el map en el map flatMap o dividirlos para simplificar.

let dict2 = [String:Int](elements: entries.flatMap { let parts = $0.componentsSeparatedByString("=") if parts.count == 2, let value = Int(parts[1]) { return (parts[0], value) } else { return nil }} )