Jak uzyskać klucz do określonego indeksu ze słownika w języku Swift?

114

Mam Dictionaryw Swift i chciałbym uzyskać klucz o określonym indeksie.

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

Wiem, że mogę iterować klucze i rejestrować je

for key in myDict.keys{

    NSLog("key = \(key)")

}

Jednak, o dziwo, coś takiego nie jest możliwe

var key : String = myDict.keys[0]

Czemu ?

the_critic
źródło
11
Pamiętaj, że słowniki Swift nie gwarantują określonej kolejności. Nie możesz więc oczekiwać na pewno, że klucze będą indeksowane w kolejności, w jakiej je umieścisz.
radex.
+1 @radex, a także chciałbym dodać, jeśli to możliwe, źródło, w którym można przeczytać więcej o Twoim oświadczeniu, byłoby bardzo wdzięczne.
SH

Odpowiedzi:

191

Dzieje się tak, ponieważ keyszwraca LazyMapCollection<[Key : Value], Key>, których nie można indeksować za pomocą Int. Jednym ze sposobów rozwiązania tego problemu jest przesunięcie słownika startIndexo liczbę całkowitą, którą chciałeś indeksować, na przykład:

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

Innym możliwym rozwiązaniem byłoby zainicjowanie tablicy z keysdanymi wejściowymi, a następnie można użyć indeksów całkowitych na wyniku:

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

Pamiętaj, że słowniki są z natury nieuporządkowane, więc nie oczekuj, że klucz w danym indeksie będzie zawsze taki sam.

Mick MacCallum
źródło
3
Prawdopodobnie byłoby to szybsze, Array(myDict)[0].0ponieważ nie kopiowałoby tablicy kluczy i nie powinno kopiować wewnętrznych struktur słownika, chociaż może.
David Berry,
5
Pamiętaj, że nie ma obietnicy dotyczącej tego, który klucz zostanie zwrócony, ale dobra uwaga na temat zwracanego typu „widoku”. Usunąłem moją odpowiedź, ponieważ tak naprawdę nie dotyczyła pytania.
Rob Napier,
9
Aby wyjaśnić, co mówi Rob, chociaż może się wydawać, że klucze są zawsze zamawiane w ten sam sposób za każdym razem, tak nie jest i jest to po prostu szczegół implementacji. Bardzo możliwe, że możesz dodać klucz „foo”, a wewnętrzna reprezentacja całkowicie zmieni kolejność słownika. Słownik to nieuporządkowana kolekcja par klucz-wartość. Dlatego powyższa odpowiedź to niebezpieczne założenia, które nie są prawdziwe.
Jack Lawrence,
8
Jeśli potrzebujesz kluczy w określonej kolejności, zachowaj ich tablicę. Następnie możesz ich używać jak myDict[keysArray[0]].
Zev Eisenberg
1
Nie działa ...'NSDictionary' is not convertible to '_ArrayBuffer<T>'
Chris
53

Swift 3: Array()może być do tego przydatny.

Weź klucz :

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

Uzyskaj wartość:

Array(myDict)[index].value
Roy
źródło
To działa dla mnie w Swift 3. Nie rozumiem jednak, dlaczego utworzona tablica jest ponownie ułożona. jakieś pomysły?
Slarty Bartfast
Dzięki, pomogło mi to
ANE
1
@josef A co z tym jest sprzeczne z intuicją? Słowniki są kluczami i parami wartości, więc idea indeksu nie rozwiązuje problemu. Dostęp do tablic uzyskuje się za pomocą indeksu, więc powoduje to zamianę słownika na tablicę, a następnie dostęp do tablicy przez jej indeks. Słownik taki jak ["a": 1, "b": 2], można przekształcić w tablicę słowników, takich jak [[key: "a", value: 1], [key: "b", value: 2]], do tego można uzyskać dostęp za pomocą indeksu.
Peter R
29

Oto małe rozszerzenie dostępu do kluczy i wartości w słowniku według indeksu:

extension Dictionary {
    subscript(i: Int) -> (key: Key, value: Value) {
        return self[index(startIndex, offsetBy: i)]
    }
}
bzz
źródło
3
API „zaawansowane” zostało usunięte w używaniu Swift 2.0 - self [self.startIndex.advancedBy (i)] -
Romain
2
Słowniki @TomSawyer nie są uporządkowane.
Jose Ramirez
12

Możesz iterować słownik i pobrać indeks z for-in i wyliczyć (jak powiedzieli inni, nie ma gwarancji, że wyjdzie w kolejności jak poniżej)

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

Jeśli chcesz najpierw posortować ...

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

następnie iteruj.

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

Jeśli chcesz stworzyć uporządkowany słownik, powinieneś zajrzeć do Generics.

Matthew Korporaal
źródło
1
a co gdybym chciał poszukać indeksu dla równego 456?
Famic Tech
2
@Max, to jest stara składnia języka Swift. Teraz możesz użyć: dict.enumerated().forEach { (index, element) in ... }
Matthew Korporaal
5

SWIFT 3. Przykład dla pierwszego elementu

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

if let firstLang = wordByLanguage.first?.key {
    print(firstLang)  // English
}
Włodzimierz Woźniak
źródło
3
A co jeśli chciałbym dostać indeks, w którym klucz jest polski?
Famic Tech
5

W Swift 3 spróbuj użyć tego kodu, aby uzyskać parę klucz-wartość (krotkę) o podanym indeksie:

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

Oto przykład wykorzystujący 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
źródło
3

SWIFT 4


Nieco nie na temat: ale tutaj jest, jeśli masz tablicę słowników, tj .: [[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
źródło
1
Jak mogę uzyskać indeks elementu, który w Twoim przykładzie ma age = xxxx?
Famic Tech
1
arrayIndex = 0, ageDictIndex = 1, Array (array_has_dictionary [arrayIndex] .keys) [ageDictIndex] = xxxx
Kristian
@FamicTech, Kris odpowiedział na twoje pytanie
Suhaib
0

Szukałem czegoś w rodzaju LinkedHashMap w Javie. Ani Swift, ani Objective-C nie mają takiego, jeśli się nie mylę.

Moją początkową myślą było zawinięcie mojego słownika w tablicę. [[String: UIImage]]ale potem zdałem sobie sprawę, że wyrywanie klucza ze słownika było szalone, Array(dict)[index].keywięc poszedłem z krotkami. Teraz moja tablica wygląda [(String, UIImage)]tak, że mogę ją pobrać przez tuple.0. Koniec z konwertowaniem go na tablicę. Tylko moje 2 centy.

newDeveloper
źródło