在Swift中,如何从字典中获取特定索引处的键?

143
我在Swift中有一个Dictionary,我想获取特定索引处的键。
var myDict : Dictionary<String,MyClass> = Dictionary<String,MyClass>()

我知道可以迭代遍历键并记录它们

for key in myDict.keys{

    NSLog("key = \(key)")

}

然而,奇怪的是,像这样的事情是不可能的

var key : String = myDict.keys[0]

为什么?

12
只是让你知道,Swift字典不保证以任何特定顺序进行排序。因此,您不能确保键按照您放置它们的顺序进行索引。 - radex
+1 @radex,如果可能的话,能否提供更多关于您陈述的来源将不胜感激。 - S.H.
10个回答

244

这是因为 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,因为它不会复制键数组,并且不应该复制字典的内部结构,尽管可能会有这种情况。 - David Berry
7
请记住,这个函数没有承诺会返回哪个键,但是需要注意它返回的是“视图”类型。由于我的回答并不适用于这个问题,因此我将其删除。 - Rob Napier
11
为了澄清Rob所说的,虽然看起来键每次总是按相同顺序排序,但实际上并非如此,这只是一种实现细节。很有可能添加键"foo"后,内部表示将完全重新排序字典。字典是一个无序的键值对集合。因此,上面的答案做出了不成立的危险假设。 - Jack Lawrence
9
如果您需要按特定顺序获取键,请保留它们的数组。然后,您可以像这样使用它们:myDict[keysArray[0]] - Zev Eisenberg
1
无法工作... 'NSDictionary' 无法转换为 '_ArrayBuffer<T>' - Chris
显示剩余5条评论

70

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
谢谢,方法是先将其转换为数组。但是在实际项目中应用它时确实很烦人。就像这个 cell.artwork.image = Array(albumDict)[indexPath.item].value.first?.artwork?.image,我使用这个长链只是为了从值中获取一个值。 - Zhou Haibo

29

这里是一个用于通过索引访问字典键和值的小扩展:

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

3
在Swift 2.0中,“advance” API已被移除,请改用-- self[self.startIndex.advancedBy(i)] --。 - Romain
3
汤姆·索耶,字典是没有顺序的。 - Hedylove

11

你可以使用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
}

如果您想创建一个有序字典,可以考虑使用泛型。


1
如果我想搜索等于456的a的索引是多少呢? - Famic Tech
2
@Max,这是旧的Swift语法。现在你可以使用:dict.enumerated().forEach { (index, element) in ... } - Matthew Korporaal

10

7
在Swift 3中,尝试使用以下代码获取给定索引处的键值对(元组):
extension Dictionary {
    subscript(i:Int) -> (key:Key,value:Value) {
        get {
            return self[index(startIndex, offsetBy: i)];
        }
    }
}

7

SWIFT 3. 第一个元素的示例

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

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

4
如果我想获取键为"Polish"的索引,应该如何操作? - Famic Tech

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
数组索引 = 0, ageDict 的索引 = 1, Array(array_has_dictionary[arrayIndex].keys)[ageDictIndex] = xxxx - Kristian
@FamicTech,Kris回答了你的问题。 - Suhaib

2

这里有一个示例,使用 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

0

我在Java中寻找类似于LinkedHashMap的东西。如果我没记错的话,Swift和Objective-C都没有这个。

我的初步想法是将字典包装在数组中。[[String: UIImage]]但后来我意识到使用Array(dict)[index].key从字典中获取键名很奇怪,所以我选择了元组。现在我的数组看起来像这样[(String, UIImage)],所以我可以通过tuple.0检索它。不再将其转换为数组。这只是我的个人见解。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接