Làm cách nào để lấy khóa tại một chỉ mục cụ thể từ Từ điển trong Swift?


114

Tôi có một Dictionarytrong Swift và tôi muốn nhận một khóa ở một chỉ mục cụ thể.

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

Tôi biết rằng tôi có thể lặp lại các phím và ghi lại chúng

for key in myDict.keys{

    NSLog("key = \(key)")

}

Tuy nhiên, kỳ lạ thay, một cái gì đó như thế này là không thể

var key : String = myDict.keys[0]

Tại sao ?


11
Bạn biết đấy, từ điển Swift không được đảm bảo theo bất kỳ thứ tự cụ thể nào. Vì vậy, bạn không thể mong đợi để chắc chắn rằng các phím được lập chỉ mục theo thứ tự bạn đặt chúng trong.
radex

+1 @radex và cũng muốn nói thêm, nếu có thể, một nguồn để đọc thêm về tuyên bố của bạn sẽ được đánh giá cao.
SH

Câu trả lời:


191

Đó là bởi vì keystrả về LazyMapCollection<[Key : Value], Key>, không thể được đăng ký bằng một Int. Một cách để xử lý điều này là nâng cấp từ điển startIndextheo số nguyên mà bạn muốn chỉ số dưới, ví dụ:

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

Một giải pháp khả thi khác sẽ là khởi tạo một mảng với keysđầu vào, sau đó bạn có thể sử dụng các chỉ số con số nguyên trên kết quả:

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

Hãy nhớ rằng, từ điển vốn không có thứ tự, vì vậy đừng mong đợi khóa tại một chỉ mục nhất định luôn giống nhau.


3
Có lẽ sẽ nhanh hơn Array(myDict)[0].0vì nó sẽ không sao chép mảng khóa và không nên sao chép cấu trúc bên trong của từ điển, mặc dù có thể.
David Berry

5
Hãy nhớ rằng không có lời hứa nào về khóa này sẽ trả về, nhưng lưu ý tốt về loại "chế độ xem" được trả về. Đã xóa câu trả lời của tôi vì nó không thực sự áp dụng cho câu hỏi.
Rob Napier

9
Để làm rõ những gì Rob đang nói, mặc dù có vẻ như các phím luôn được sắp xếp giống nhau mọi lúc, nhưng đây không phải là trường hợp mà chỉ đơn giản là một chi tiết triển khai. Rất có thể bạn có thể thêm khóa "foo" và phần biểu diễn bên trong sẽ sắp xếp lại hoàn toàn từ điển. Từ điển là một tập hợp các cặp khóa-giá trị không có thứ tự . Do đó, câu trả lời trên đang đưa ra những giả định nguy hiểm không đúng.
Jack Lawrence

8
Nếu bạn cần các khóa theo một thứ tự cụ thể, hãy giữ một mảng trong số đó. Sau đó, bạn có thể sử dụng chúng như thế nào myDict[keysArray[0]].
Zev Eisenberg

1
Không hoạt động ...'NSDictionary' is not convertible to '_ArrayBuffer<T>'
Chris

53

Swift 3: Array()có thể hữu ích để làm điều này.

Nhận chìa khóa:

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

Nhận giá trị:

Array(myDict)[index].value

Điều này phù hợp với tôi đối với Swift 3. Tuy nhiên, không hiểu tại sao Mảng đã tạo lại được sắp xếp lại. Có suy nghĩ gì không?
Slarty Bartfast

Cảm ơn điều này đã giúp tôi
ANE

1
@josef Điều gì về nó là phản trực quan? Từ điển là các cặp giá trị, khóa, vì vậy ý ​​tưởng về một chỉ mục không cố định. Mảng được truy cập bằng chỉ mục, do đó, điều này biến một từ điển THÀNH Mảng, sau đó truy cập mảng bằng chỉ mục của nó. Một từ điển giống như ["a": 1, "b": 2], có thể được biến thành một mảng các từ điển như [[key: "a", value: 1], [key: "b", value: 2]], sau đó có thể truy cập bằng chỉ mục.
Peter R

29

Đây là một tiện ích mở rộng nhỏ để truy cập các khóa và giá trị trong từ điển theo chỉ mục:

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

3
API 'nâng cao' đã bị xóa trong việc sử dụng Swift 2.0 - self [self.startIndex.advancedBy (i)] -
Romain

2
Từ điển @TomSawyer không được sắp xếp.
Jose Ramirez

12

Bạn có thể lặp lại từ điển và lấy một chỉ mục có bổ sung và liệt kê (giống như những người khác đã nói, không có gì đảm bảo rằng nó sẽ xuất hiện theo thứ tự như bên dưới)

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

Nếu bạn muốn sắp xếp trước ..

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

sau đó lặp lại.

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

Nếu bạn muốn tạo một từ điển có thứ tự, bạn nên xem xét Generics.


1
Điều gì sẽ xảy ra nếu tôi muốn tìm kiếm chỉ số cho bằng 456?
Famic Tech,

2
@Max, đây là cú pháp Swift cũ. Bây giờ bạn có thể sử dụng: dict.enumerated().forEach { (index, element) in ... }
Matthew Korporaal

8

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

Nếu bạn cần sử dụng các khóa hoặc giá trị của từ điển với một API có phiên bản Mảng, hãy khởi tạo một mảng mới với thuộc tính khóa hoặc giá trị:

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

5

SWIFT 3. Ví dụ cho phần tử đầu tiên

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

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

3
Điều gì sẽ xảy ra nếu tôi muốn lấy chỉ mục trong đó khóa là tiếng Ba Lan?
Famic Tech,

5

Trong Swift 3, hãy thử sử dụng mã này để nhận Cặp khóa-giá trị (tuple) ở chỉ mục nhất định:

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

3

Đây là một ví dụ, sử dụng 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


Hơi lạc đề: Nhưng đây là nếu bạn có Mảng từ điển, tức là: [[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
Làm cách nào để lấy chỉ mục của mục có age = xxxx trong ví dụ của bạn?
Famic Tech

1
arrayIndex = 0, ageDictIndex = 1, Array (array_has_dictionary [arrayIndex] .keys) [ageDictIndex] = xxxx
Kristian

@FamicTech, Kris đã trả lời câu hỏi của bạn
Suhaib,

0

Tôi đang tìm kiếm thứ gì đó giống như một LinkedHashMap trong Java. Cả Swift và Objective-C đều không có nếu tôi không nhầm.

Suy nghĩ ban đầu của tôi là bọc từ điển của tôi trong một Mảng. [[String: UIImage]]nhưng sau đó tôi nhận ra rằng việc lấy chìa khóa từ từ điển là một việc kỳ lạ Array(dict)[index].keynên tôi đã đi với Tuples. Bây giờ mảng của tôi trông giống như [(String, UIImage)]vậy tôi có thể truy xuất nó bằng cách tuple.0. Không cần chuyển đổi nó thành Mảng. Chỉ 2 xu của tôi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.