Comment obtenir la clé d'un index spécifique à partir d'un dictionnaire dans Swift?

114

J'ai un Dictionarydans Swift et je voudrais obtenir une clé à un index spécifique.

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

Je sais que je peux parcourir les clés et les enregistrer

for key in myDict.keys{

    NSLog("key = \(key)")

}

Cependant, curieusement, quelque chose comme ça n'est pas possible

var key : String = myDict.keys[0]

Pourquoi ?

le_critique
la source
11
Juste pour que vous le sachiez, les dictionnaires Swift ne sont pas garantis dans un ordre spécifique. Vous ne pouvez donc pas vous attendre à ce que les clés soient indexées dans l'ordre dans
lequel
+1 @radex et voudrait également ajouter, si possible, une source pour en savoir plus sur votre déclaration serait grandement appréciée.
SH

Réponses:

191

C'est parce que les keysretours LazyMapCollection<[Key : Value], Key>, qui ne peuvent pas être indiqués avec un Int. Une façon de gérer cela consiste à faire avancer le dictionnaire de startIndexl'entier que vous vouliez indiquer, par exemple:

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

Une autre solution possible serait d'initialiser un tableau avec keyscomme entrée, vous pouvez alors utiliser des indices entiers sur le résultat:

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

N'oubliez pas que les dictionnaires ne sont pas ordonnés par nature, alors ne vous attendez pas à ce que la clé d'un index donné soit toujours la même.

Mick MacCallum
la source
3
Il serait probablement plus rapide Array(myDict)[0].0car il ne copierait pas le tableau de clés et ne devrait pas copier les structures internes du dictionnaire, bien que cela puisse être le cas.
David Berry
5
Gardez à l'esprit qu'il n'y a aucune promesse sur la clé qui sera renvoyée, mais bonne note sur le type "vue" qui est retourné. J'ai supprimé ma réponse car elle ne s'appliquait pas réellement à la question.
Rob Napier
9
Pour clarifier ce que Rob dit, bien qu'il puisse sembler que les clés sont toujours ordonnées de la même manière à chaque fois, ce n'est pas le cas et il s'agit simplement d'un détail d'implémentation. Il est très possible que vous ajoutiez la clé "foo" et la représentation interne réorganisera complètement le dictionnaire. Un dictionnaire est une collection non ordonnée de paires clé-valeur. Par conséquent, la réponse ci-dessus fait des hypothèses dangereuses qui ne sont pas vraies.
Jack Lawrence
8
Si vous avez besoin des clés dans un ordre spécifique, conservez-en un tableau. Ensuite, vous pouvez les utiliser comme myDict[keysArray[0]].
Zev Eisenberg
1
Ne fonctionne pas ...'NSDictionary' is not convertible to '_ArrayBuffer<T>'
Chris
53

Swift 3: Array()peut être utile pour cela.

Obtenir la clé :

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

Obtenez de la valeur:

Array(myDict)[index].value
roy
la source
Cela fonctionne pour moi pour Swift 3. Je ne comprends pas pourquoi le tableau créé est réorganisé. Des pensées?
Slarty Bartfast
Merci cela m'a aidé
ANE
1
@josef Qu'est-ce que c'est contre-intuitif? Les dictionnaires sont des paires clé-valeur, donc l'idée d'un index ne résout pas. Les tableaux sont accessibles par index, ce qui transforme un dictionnaire EN un tableau, puis accède au tableau par son index. Un dictionnaire comme ["a": 1, "b": 2], peut être transformé en un tableau de dictionnaires comme [[key: "a", value: 1], [key: "b", value: 2]], cela peut ensuite être consulté par index.
Peter R
29

Voici une petite extension pour accéder aux clés et valeurs dans le dictionnaire par index:

extension Dictionary {
    subscript(i: Int) -> (key: Key, value: Value) {
        return self[index(startIndex, offsetBy: i)]
    }
}
bzz
la source
3
L'API 'advanced' a été supprimée dans l'utilisation de Swift 2.0 - self [self.startIndex.advancedBy (i)] -
Romain
2
Les dictionnaires @TomSawyer ne sont pas classés.
Jose Ramirez
12

Vous pouvez parcourir un dictionnaire et saisir un index avec for-in et énumérer (comme d'autres l'ont dit, il n'y a aucune garantie qu'il sortira dans l'ordre comme ci-dessous)

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 vous souhaitez effectuer le tri en premier.

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

puis itérer.

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

Si vous souhaitez créer un dictionnaire ordonné, vous devez vous pencher sur les génériques.

Matthew Korporaal
la source
1
et si je voulais rechercher ce que l'indice était égal à 456?
Famic Tech
2
@Max, c'est l'ancienne syntaxe Swift. Vous pouvez maintenant utiliser: dict.enumerated().forEach { (index, element) in ... }
Matthew Korporaal
8

Depuis https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/CollectionTypes.html :

Si vous devez utiliser les clés ou les valeurs d'un dictionnaire avec une API qui prend une instance de Array, initialisez un nouveau tableau avec la propriété keys ou values:

let airportCodes = [String](airports.keys) // airportCodes is ["TYO", "LHR"]   
let airportNames = [String](airports.values) // airportNames is ["Tokyo", "London Heathrow"]
Jack
la source
5

SWIFT 3. Exemple pour le premier élément

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

if let firstLang = wordByLanguage.first?.key {
    print(firstLang)  // English
}
Włodzimierz Woźniak
la source
3
Et si je voulais obtenir l'index où la clé est polonaise?
Famic Tech
5

Dans Swift 3, essayez d'utiliser ce code pour obtenir une paire clé-valeur (tuple) à un index donné:

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

Voici un exemple, utilisant 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
la source
3

SWIFT 4


Légèrement hors sujet: mais voici si vous avez un tableau de dictionnaires, c'est-à-dire: [[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
la source
1
Comment puis-je obtenir l'index de l'élément qui a age = xxxx dans votre exemple?
Famic Tech
1
arrayIndex = 0, ageDictIndex = 1, Array (array_has_dictionary [arrayIndex] .keys) [ageDictIndex] = xxxx
Kristian
@FamicTech, Kris a répondu à votre question
Suhaib
0

Je cherchais quelque chose comme un LinkedHashMap en Java. Ni Swift ni Objective-C n'en ont un si je ne me trompe pas.

Ma première pensée était d'envelopper mon dictionnaire dans un tableau. [[String: UIImage]]mais ensuite j'ai réalisé que saisir la clé du dictionnaire était farfelu avec Array(dict)[index].keydonc je suis allé avec Tuples. Maintenant, mon tableau ressemble à [(String, UIImage)]ce que je peux récupérer par tuple.0. Plus besoin de le convertir en un tableau. Juste mes 2 cents.

nouveauDéveloppeur
la source