ios objective-c swift dictionary nsdictionary

ios - Rápido equivalente a `[NSDictionary initWithObjects: forKeys:]`



objective-c swift (5)

¿Existe un equivalente para el Dictionary nativo de Swift a [NSDictionary initWithObjects: forKeys:] ?

Digamos que tengo dos matrices con claves y valores y quiero ponerlas en un diccionario. En Objective-C lo haría así:

NSArray *keys = @[@"one", @"two", @"three"]; NSArray *values = @[@1, @2, @3]; NSDictionary *dict = [[NSDictionary alloc] initWithObjects: values forKeys: keys];

Por supuesto, puedo iterar con un contador a través de ambas matrices, usar un var dict: [String:Int] y agregar cosas paso a paso. Pero eso no parece ser una buena solución. Usar zip y enumerate son probablemente mejores formas de iterar sobre ambos al mismo tiempo. Sin embargo, este enfoque significa tener un diccionario mutable, no uno inmutable.

let keys = ["one", "two", "three"] let values = [1, 2, 3] // ??? let dict: [String:Int] = ["one":1, "two":2, "three":3] // expected result


A partir de Swift 4 , puede crear un diccionario directamente a partir de una secuencia de pares clave / valor:

let keys = ["one", "two", "three"] let values = [1, 2, 3] let dict = Dictionary(uniqueKeysWithValues: zip(keys, values)) print(dict) // ["one": 1, "three": 3, "two": 2]

Esto supone que todas las claves son diferentes, de lo contrario se cancelará con una excepción de tiempo de ejecución.

Si no se garantiza que las claves sean distintas, puede hacerlo

let keys = ["one", "two", "one"] let values = [1, 2, 3] let dict = Dictionary(zip(keys, values), uniquingKeysWith: { $1 }) print(dict) // ["one": 3, "two": 2]

El segundo argumento es un cierre que determina qué valor "gana" en el caso de claves duplicadas.


Simplemente puede usar el equivalente Swift de initWithObjects:forKeys:

let keys = ["one", "two", "three"] let values = [1, 2, 3] var dict = NSDictionary.init(objects: values, forKeys: keys)


Trabajando pura solución Swift con structs. Use zip para recorrer sus dos matrices como una tupla, y luego cree un diccionario para cada clave, valor en la tupla.

struct SomeStruct { var someVal: Int? } var keys = [String]() var values = [SomeStruct]() for index in 0...5 { keys.append(String(index)) values.append(SomeStruct(someVal: index)) } var dict = [String : Any]() for (key, value) in zip(keys, values) { dict[key] = value } print(dict) // "["4": SomeStruct(someVal: Optional(4)), "2": SomeStruct(someVal: Optional(2)), "1": SomeStruct(someVal: Optional(1)), "5": SomeStruct(someVal: Optional(5)), "0": SomeStruct(someVal: Optional(0)), "3": SomeStruct(someVal: Optional(3))]"

También forEach usar forEach en zip :

var dict = [String : Any]() zip(keys, values).forEach { dict[$0.0] = $0.1 } print(dict) // "["4": SomeStruct(someVal: Optional(4)), "2": SomeStruct(someVal: Optional(2)), "1": SomeStruct(someVal: Optional(1)), "5": SomeStruct(someVal: Optional(5)), "0": SomeStruct(someVal: Optional(0)), "3": SomeStruct(someVal: Optional(3))]/n"


Una línea, usando zip y reduce :

let dict = zip(keys, values).reduce([String:Int]()){ var d = $0; d[$1.0] = $1.1; return d }

Puede acortar la expresión de reduce definiendo el operador + para un Dictionary y una tuple :

func +<K,V>(lhs: [K:V], rhs: (K, V)) -> [K:V] { var result = lhs result[rhs.0] = rhs.1 return result } let dict = zip(keys, values).reduce([String:Int](), combine: +)


let keys = ["one", "two", "three"] let values = [1, 2, 3] func createDict<K:Hashable,V>(keys: [K], values:[V])->[K:V] { var dict: [K:V] = [:] // add validity checks here by yourself ! // and return early, or throw an error ... keys.enumerate().forEach { (index,element) -> () in dict[element] = values[index] } return dict } let dict = createDict(keys, values: values) // ["one": 1, "three": 3, "two": 2] let dict2:[Int:Any] = createDict([1,2,3,4,5], values: [true,"two",3.4,5,[1,2,3]]) // [5: [1, 2, 3], 2: "two", 3: 3.4, 1: true, 4: 5]

¿Cuál es la diferencia si se compara con la solución zip? difícil de decir ... para mí, la anotación de tipo zip es el mayor problema

let a:Zip2Sequence<[Int],[Any]> = zip([1,2,3,4,5], [true,"two",3.4,5,[1,2,3]]) var d:[Int:Any] = [:] a.forEach { (key, value) -> () in d[key] = value } print(d) // [5: [1, 2, 3], 2: "two", 3: 3.4, 1: true, 4: 5]

pero enumerar la solución también es un poco más rápido