Как мне получить ключ по определенному индексу из словаря в 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]

Зачем ?

the_critic
источник
11
Просто чтобы вы знали, словари Swift не гарантируются в каком-либо определенном порядке. Так что нельзя быть уверенным, что ключи будут проиндексированы в том порядке, в котором вы их разместили.
radex 08
+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
Имейте в виду, что нет никаких обещаний о том, какой ключ это вернет, но есть хорошее примечание о возвращаемом типе "представления". Мой ответ удален, так как он не относится к вопросу.
Роб Напье
9
Чтобы прояснить, что говорит Роб, хотя может показаться, что ключи всегда заказываются одинаково каждый раз, это не так, и это просто деталь реализации. Очень возможно, что вы можете добавить ключ «foo», и внутреннее представление полностью изменит порядок словаря. Словарь - это неупорядоченный набор пар ключ-значение. Следовательно, приведенный выше ответ делает опасные предположения, которые не соответствуют действительности.
Джек Лоуренс
8
Если вам нужны ключи в определенном порядке, сохраните их массив. Тогда вы можете использовать их как myDict[keysArray[0]].
Зев Айзенберг
1
Не работает ...'NSDictionary' is not convertible to '_ArrayBuffer<T>'
Крис,
53

Swift 3: Array()может быть полезно для этого.

Получить ключ:

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

Получите ценность:

Array(myDict)[index].value
Рой
источник
У меня это работает для Swift 3. Не понимаю, почему созданный массив переупорядочивается. Есть предположения?
Slarty Bartfast
Спасибо, это помогло мне
ANE
1
@josef Что в этом нелогичного? Словари - это пары ключ-значение, поэтому идея индекса не фиксируется. Доступ к массивам осуществляется по индексу, поэтому это превращает словарь в массив, а затем обращается к массиву по его индексу. Словарь, например ["a": 1, "b": 2], можно превратить в массив словарей, например [[key: "a", value: 1], [key: "b", value: 2]], тогда к нему можно будет получить доступ по индексу.
Peter R
29

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

extension Dictionary {
    subscript(i: Int) -> (key: Key, value: Value) {
        return self[index(startIndex, offsetBy: i)]
    }
}
бзз
источник
3
API 'advance' был удален в Swift 2.0 use - self [self.startIndex.advancedBy (i)] -
Romain
2
Словари @TomSawyer не заказываются.
Хосе Рамирес
12

Вы можете перебирать словарь и получать индекс с помощью for-in и enumerate (как говорили другие, нет никакой гарантии, что он будет упорядочен, как показано ниже)

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, который принимает экземпляр Array, инициализируйте новый массив с помощью свойства keys или values:

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
Suhaib
источник
1
Как я могу получить индекс элемента с возрастом = xxxx в вашем примере?
Famic Tech
1
arrayIndex = 0, ageDictIndex = 1, Array (array_has_dictionary [arrayIndex] .keys) [ageDictIndex] = xxxx
Кристиан
@FamicTech, Крис ответил на ваш вопрос
Suhaib
0

Я искал что-то вроде LinkedHashMap на Java. Ни у Swift, ни у Objective-C его нет, если я не ошибаюсь.

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

newDeveloper
источник