Як отримати ключ у конкретному покажчику зі словника в Swift?


114

У мене є DictionarySwift, і я хотів би отримати ключ за певним індексом.

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

Я знаю, що можу перебрати ключі та записати їх

for key in myDict.keys{

    NSLog("key = \(key)")

}

Однак, як не дивно, щось подібне неможливо

var key : String = myDict.keys[0]

Чому?


11
Просто так ви знаєте, що словники Swift не гарантуються в певному порядку. Таким чином, ви не можете сподіватися напевно, що ключі будуть проіндексовані в тому порядку, який ви їх ввели.
radex

+1 @radex, а також хотіли б додати, якщо можливо, джерело, щоб прочитати більше про вашу заяву, було б дуже вдячно.
SH

Відповіді:


191

Це тому, що keysповернення LazyMapCollection<[Key : Value], Key>, які не можна підписати на Int. Один із способів вирішити це - просунути словник startIndexна ціле число, яке ви хотіли підписати, наприклад:

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

Іншим можливим рішенням буде ініціалізація масиву з keysвведенням, тоді ви можете використовувати цілі підписки на результат:

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

Пам'ятайте, що словники за своєю суттю не упорядковані, тому не сподівайтеся, що ключ у заданому індексі завжди буде однаковим.


3
Напевно, це буде швидше, Array(myDict)[0].0оскільки він не копіює масив ключів і не повинен копіювати внутрішні структури словника, хоча це може бути.
Девід Беррі

5
Майте на увазі, що немає обіцянки про те, який ключ повернеться, але хороша примітка про тип "view", який повертається. Видалили свою відповідь, оскільки вона насправді не стосувалася питання.
Роб Нап'єр

9
Щоб уточнити, що говорить Роб, хоча може здатися, що ключі завжди замовляються однаково кожен раз, це не так і є просто деталізацією реалізації. Цілком можливо, що ви можете додати ключ "foo", і внутрішнє представлення повністю змінить порядок словника. Словник - це не упорядкована колекція пар ключових значень. Тому відповідь, наведена вище, робить небезпечні припущення, які не відповідають дійсності.
Джек Лоуренс

8
Якщо вам потрібні ключі в певному порядку, зберігайте їх масив. Тоді ви можете використовувати їх як myDict[keysArray[0]].
Zev Eisenberg

1
Не працює ...'NSDictionary' is not convertible to '_ArrayBuffer<T>'
Chris

53

Swift 3: Array()може бути корисним для цього.

Отримати ключ:

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

Отримайте вартість:

Array(myDict)[index].value

Це працює для мене для Swift 3. Не розумію, чому створений масив перестановлений, хоча. Будь-які думки?
Slarty Bartfast

Дякую, це допомогло мені
ANE

1
@josef Що з цим суперечить інтуїтивно? Словники є ключовими, парами значень, тому ідея індексу не фіксується. Масиви отримують доступ до індексу, тому це перетворює словник INTO у масив, а потім отримує доступ до масиву за його індексом. Словник на зразок ["a": 1, "b": 2]може бути перетворений на масив словників на зразок [[key: "a", value: 1], [key: "b", value: 2]], потім це можна отримати за допомогою індексу.
Петро Р

29

Ось невелике розширення для доступу до ключів та значень у словнику за індексом:

extension Dictionary {
    subscript(i: Int) -> (key: Key, value: Value) {
        return self[index(startIndex, offsetBy: i)]
    }
}

3
API "заздалегідь" було видалено під час використання Swift 2.0 - self [self.startIndex.advancedBy (i)] -
Romain

2
@TomSawyer словники не впорядковані.
Хосе Рамірес

12

Ви можете перебирати словник і захоплювати індекс за допомогою in-in і перелічувати (як інші казали, немає гарантії, що він вийде впорядкованим, як нижче)

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

Якщо ви хочете сортувати спочатку ..

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

потім повторіть.

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

Якщо ви хочете створити впорядкований словник, слід заглянути в Generics.


1
Що робити, якщо я хотів шукати, який індекс був рівним 456?
Famic Tech

2
@Max, це старий синтаксис Swift. Тепер ви можете використовувати: dict.enumerated().forEach { (index, element) in ... }
Матвій Корпораал

8

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

Якщо вам потрібно використовувати ключі або значення словника з API, який приймає екземпляр масиву, ініціалізуйте новий масив із властивістю ключів або значень:

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

5

SWIFT 3. Приклад першого елемента

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

if let firstLang = wordByLanguage.first?.key {
    print(firstLang)  // English
}

3
Що робити, якщо я хотів отримати індекс, де ключовим є польський?
Famic Tech

5

У Swift 3 спробуйте скористатися цим кодом, щоб отримати ключ-значення пари (кортеж) за заданим індексом:

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

3

Ось приклад, використовуючи 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

3

SWIFT 4


Трохи поза темою: Але ось якщо у вас є масив словників, тобто: [[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

1
Як я можу отримати у вашому прикладі індекс елемента, який має вік = xxxx?
Famic Tech

1
arrayIndex = 0, ageDictIndex = 1, масив (array_has_dictionary [arrayIndex] .keys) [ageDictIndex] = xxxx
Крістіан

@FamicTech, Kris відповів на ваше запитання
Suhaib

0

Я шукав щось на зразок LinkedHashMap на Java. Ні Swift, ні Objective-C не мають жодного, якщо я не помиляюся.

Моя початкова думка полягала в тому, щоб загорнути свій словник у масив. [[String: UIImage]]але потім я зрозумів, що схопити ключ зі словника було нерозумно, Array(dict)[index].keyтому я пішов з Tuples. Тепер мій масив виглядає [(String, UIImage)]так, що я можу отримати його tuple.0. Більше не перетворювати його в масив. Всього мої 2 копійки.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.