¿Cómo obtengo la clave de un índice específico de un diccionario en Swift?

114

Tengo un DictionarySwift y me gustaría obtener una clave en un índice específico.

var myDict : Dictionary<String,MyClass> = Dictionary<String,MyClass>()

Sé que puedo iterar sobre las claves y registrarlas

for key in myDict.keys{

    NSLog("key = \(key)")

}

Sin embargo, curiosamente, algo como esto no es posible.

var key : String = myDict.keys[0]

Por qué ?

el crítico
fuente
11
Para tu información, no se garantiza que los diccionarios Swift estén en un orden específico. Por lo tanto, no puede esperar con certeza que las claves se indexen en el orden en que las puso.
radex
+1 @radex y también me gustaría agregar, si es posible, una fuente para leer más sobre su declaración sería muy apreciado.
SH

Respuestas:

191

Eso es porque las keysdevoluciones LazyMapCollection<[Key : Value], Key>, que no se pueden suscribir con un Int. Una forma de manejar esto es avanzar el diccionario startIndexpor el número entero que desea subíndice, por ejemplo:

let intIndex = 1 // where intIndex < myDictionary.count
let index = myDictionary.index(myDictionary.startIndex, offsetBy: intIndex)
myDictionary.keys[index]

Otra posible solución sería inicializar una matriz con keyscomo entrada, luego puede usar subíndices enteros en el resultado:

let firstKey = Array(myDictionary.keys)[0] // or .first

Recuerde, los diccionarios están inherentemente desordenados, así que no espere que la clave en un índice dado sea siempre la misma.

Mick MacCallum
fuente
3
Probablemente más rápido sería Array(myDict)[0].0ya que no copiaría la matriz de claves, y no debería copiar las estructuras internas del diccionario, aunque podría hacerlo.
David Berry
5
Tenga en cuenta que no hay ninguna promesa sobre qué clave devolverá, pero una buena nota sobre el tipo de "vista" que se devuelve. Eliminé mi respuesta ya que en realidad no se aplicaba a la pregunta.
Rob Napier
9
Para aclarar lo que dice Rob, si bien puede parecer que las claves siempre están ordenadas de la misma manera cada vez, este no es el caso y es simplemente un detalle de implementación. Es muy posible que pueda agregar la clave "foo" y la representación interna reordenará completamente el diccionario. Un diccionario es una colección desordenada de pares clave-valor. Por lo tanto, la respuesta anterior es hacer suposiciones peligrosas que no son ciertas.
Jack Lawrence
8
Si necesita las claves en un orden específico, mantenga una matriz de ellas. Entonces puedes usarlos como myDict[keysArray[0]].
Zev Eisenberg
1
No funciona ...'NSDictionary' is not convertible to '_ArrayBuffer<T>'
Chris
53

Swift 3: Array() puede ser útil para hacer esto.

Obtener la clave :

let index = 5 // Int Value
Array(myDict)[index].key

Obtener valor:

Array(myDict)[index].value
Roy
fuente
Esto me funciona para Swift 3. Sin embargo, no entiendo por qué la matriz creada se reorganiza. ¿Alguna idea?
Slarty Bartfast
Gracias, esto me ayudó
ANE
1
@josef ¿Qué pasa con lo contrario a la intuición? Los diccionarios son pares clave, de valor, por lo que la idea de un índice no se soluciona. Se accede a las matrices por índice, por lo que esto convierte un diccionario EN una matriz, y luego accede a la matriz por su índice. Un diccionario como ["a": 1, "b": 2], se puede convertir en una serie de diccionarios como [[key: "a", value: 1], [key: "b", value: 2]], esto luego se puede acceder por índice.
Peter R
29

Aquí hay una pequeña extensión para acceder a claves y valores en el diccionario por índice:

extension Dictionary {
    subscript(i: Int) -> (key: Key, value: Value) {
        return self[index(startIndex, offsetBy: i)]
    }
}
bzz
fuente
3
La API 'avanzada' se ha eliminado en el uso de Swift 2.0 - self [self.startIndex.advancedBy (i)] -
Romain
2
Los diccionarios de @TomSawyer no están ordenados.
Jose Ramirez
12

Puede iterar sobre un diccionario y tomar un índice con for-in y enumerar (como han dicho otros, no hay garantía de que saldrá ordenado como se muestra a continuación)

let dict = ["c": 123, "d": 045, "a": 456]

for (index, entry) in enumerate(dict) {
    println(index)   // 0       1        2
    println(entry)   // (d, 45) (c, 123) (a, 456)
}

Si desea ordenar primero ...

var sortedKeysArray = sorted(dict) { $0.0 < $1.0 }
println(sortedKeysArray)   // [(a, 456), (c, 123), (d, 45)]

var sortedValuesArray = sorted(dict) { $0.1 < $1.1 }
println(sortedValuesArray) // [(d, 45), (c, 123), (a, 456)]

luego iterar.

for (index, entry) in enumerate(sortedKeysArray) {
    println(index)    // 0   1   2
    println(entry.0)  // a   c   d
    println(entry.1)  // 456 123 45
}

Si desea crear un diccionario ordenado, debe buscar en Genéricos.

Matthew Korporaal
fuente
1
¿Y si quisiera buscar lo que el índice era igual a 456?
Famic Tech
2
@Max, esta es la sintaxis antigua de Swift. Ahora puede usar: dict.enumerated().forEach { (index, element) in ... }
Matthew Korporaal
5

SWIFT 3. Ejemplo para el primer elemento

let wordByLanguage = ["English": 5, "Spanish": 4, "Polish": 3, "Arabic": 2]

if let firstLang = wordByLanguage.first?.key {
    print(firstLang)  // English
}
Włodzimierz Woźniak
fuente
3
¿Y si quisiera obtener el índice donde la clave es polaca?
Famic Tech
5

En Swift 3, intente usar este código para obtener el par clave-valor (tupla) en el índice dado:

extension Dictionary {
    subscript(i:Int) -> (key:Key,value:Value) {
        get {
            return self[index(startIndex, offsetBy: i)];
        }
    }
}
Michał Ziobro
fuente
3

Aquí hay un ejemplo, usando Swift 1.2

var person = ["name":"Sean", "gender":"male"]
person.keys.array[1] // "gender", get a dictionary key at specific index 
person.values.array[1] // "male", get a dictionary value at specific index
Sean Chen
fuente
3

SWIFT 4


Un poco fuera de tema: pero aquí está si tiene una matriz de diccionarios, es decir: [[String: String]]

var array_has_dictionary = [ // Start of array

   // Dictionary 1

   [ 
     "name" : "xxxx",
     "age" : "xxxx",
     "last_name":"xxx"
   ],

   // Dictionary 2

   [ 
     "name" : "yyy",
     "age" : "yyy",
     "last_name":"yyy"
   ],

 ] // end of array


cell.textLabel?.text =  Array(array_has_dictionary[1])[1].key
// Output: age -> yyy
Suhaib
fuente
1
¿Cómo puedo obtener el índice del elemento que tiene age = xxxx en su ejemplo?
Famic Tech
1
arrayIndex = 0, ageDictIndex = 1, Array (array_has_dictionary [arrayIndex] .keys) [ageDictIndex] = xxxx
Kristian
@FamicTech, Kris respondió a su pregunta
Suhaib
0

Estaba buscando algo como LinkedHashMap en Java. Ni Swift ni Objective-C tienen uno si no me equivoco.

Mi pensamiento inicial fue envolver mi diccionario en una matriz. [[String: UIImage]]pero luego me di cuenta de que agarrar la clave del diccionario era una locura, Array(dict)[index].keyasí que fui con Tuples. Ahora mi matriz se ve [(String, UIImage)]así que puedo recuperarla tuple.0. No más convertirlo en una matriz. Solo mis 2 centavos.

nuevo Desarrollador
fuente