Como faço para obter a chave em um índice específico de um dicionário no Swift?

114

Eu tenho um Dictionaryem Swift e gostaria de obter uma chave em um índice específico.

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

Eu sei que posso iterar nas chaves e registrá-las

for key in myDict.keys{

    NSLog("key = \(key)")

}

No entanto, estranhamente, algo assim não é possível

var key : String = myDict.keys[0]

Por quê ?

the_critic
fonte
11
É importante que você saiba que não há garantia de que os dicionários Swift estejam em uma ordem específica. Portanto, você não pode esperar com certeza que as chaves serão indexadas na ordem em que as inseriu.
radex
+1 @radex e também gostaria de adicionar, se possível, uma fonte para ler mais sobre sua declaração seria muito apreciada.
SH

Respostas:

191

Isso ocorre porque keysretorna LazyMapCollection<[Key : Value], Key>, que não pode ser subscrito por um Int. Uma maneira de lidar com isso é avançar o dicionário startIndexpelo número inteiro que você deseja subscrever, por exemplo:

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

Outra solução possível seria inicializar uma matriz com keyscomo entrada, então você pode usar subscritos inteiros no resultado:

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

Lembre-se de que os dicionários são inerentemente desordenados, então não espere que a chave em um determinado índice seja sempre a mesma.

Mick MacCallum
fonte
3
Provavelmente mais rápido seria, Array(myDict)[0].0já que ele não copiaria o array keys e não deveria copiar as estruturas internas do dicionário, embora pudesse.
David Berry
5
Lembre-se de que não há promessa sobre qual chave isso retornará, mas uma boa observação sobre o tipo de "visualização" que é retornado. Excluí minha resposta, pois ela não se aplicava à pergunta.
Rob Napier
9
Para esclarecer o que Rob está dizendo, embora possa parecer que as chaves são sempre ordenadas da mesma forma, esse não é o caso e é simplesmente um detalhe de implementação. É muito possível que você adicione a chave "foo" e a representação interna reordene completamente o dicionário. Um dicionário é uma coleção não ordenada de pares chave-valor. Portanto, a resposta acima está fazendo suposições perigosas que não são verdadeiras.
Jack Lawrence
8
Se você precisar das chaves em uma ordem específica, mantenha uma matriz delas. Então você pode usá-los como myDict[keysArray[0]].
Zev Eisenberg
1
Não funciona ...'NSDictionary' is not convertible to '_ArrayBuffer<T>'
Chris,
53

Swift 3: Array()pode ser útil para fazer isso.

Obtenha a chave:

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

Obter valor :

Array(myDict)[index].value
Roy
fonte
Isso funciona para mim para o Swift 3. Não entendo porque o Array criado foi reorganizado. Alguma ideia?
Slarty Bartfast
Obrigado, isso me ajudou
ANE
1
@josef E isso é contra-intuitivo? Dicionários são pares de chave e valor, então a ideia de um índice não é fixa. Os arrays são acessados ​​por índice, então isso transforma um dicionário em um Array e, em seguida, acessa o array por seu índice. Um dicionário como ["a": 1, "b": 2], pode ser transformado em uma série de dicionários como [[key: "a", value: 1], [key: "b", value: 2]], este pode então ser acessado por índice.
Peter R
29

Aqui está uma pequena extensão para acessar chaves e valores no dicionário por índice:

extension Dictionary {
    subscript(i: Int) -> (key: Key, value: Value) {
        return self[index(startIndex, offsetBy: i)]
    }
}
bzz
fonte
3
API 'advance' foi removida no uso do Swift 2.0 - self [self.startIndex.advancedBy (i)] -
Romain
2
Os dicionários @TomSawyer não são solicitados.
Jose Ramirez
12

Você pode iterar em um dicionário e pegar um índice com for-in e enumerar (como outros disseram, não há garantia de que sairá ordenado como abaixo)

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)
}

Se você quiser classificar primeiro ..

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)]

em seguida, itere.

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

Se você deseja criar um dicionário ordenado, deve procurar Genéricos.

Matthew Korporaal
fonte
1
e se eu quisesse pesquisar o índice para um igual a 456?
Famic Tech
2
@Max, esta é a sintaxe Swift antiga. Agora você pode usar: dict.enumerated().forEach { (index, element) in ... }
Matthew Korporaal
5

SWIFT 3. Exemplo para o primeiro elemento

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

if let firstLang = wordByLanguage.first?.key {
    print(firstLang)  // English
}
Włodzimierz Woźniak
fonte
3
E se eu quisesse obter o índice em que a chave é polonês?
Famic Tech
5

No Swift 3, tente usar este código para obter o par de valores-chave (tupla) em determinado índice:

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

Aqui está um exemplo, 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
fonte
3

SWIFT 4


Um pouco fora do tópico: mas aqui está se você tiver uma matriz de dicionários, por exemplo: [[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
fonte
1
Como posso obter o índice do item que tem idade = xxxx em seu exemplo?
Famic Tech
1
arrayIndex = 0, ageDictIndex = 1, Array (array_has_dictionary [arrayIndex] .keys) [ageDictIndex] = xxxx
Kristian
@FamicTech, Kris respondeu à sua pergunta
Suhaib
0

Eu estava procurando por algo como um LinkedHashMap em Java. Nem o Swift nem o Objective-C têm um, se não me engano.

Meu pensamento inicial foi envolver meu dicionário em um Array. [[String: UIImage]]mas então percebi que pegar a chave do dicionário era uma loucura, Array(dict)[index].keyentão optei por Tuplas. Agora meu array está assim, [(String, UIImage)]então posso recuperá-lo por tuple.0. Chega de convertê-lo em um Array. Apenas meus 2 centavos.

newDeveloper
fonte