Xác định xem từ điển Swift có chứa khóa hay không và nhận bất kỳ giá trị nào của nó


260

Tôi hiện đang sử dụng các đoạn mã (vụng về) sau đây để xác định xem từ điển Swift (không trống) có chứa khóa đã cho hay không và để lấy một giá trị (bất kỳ) từ cùng một từ điển.

Làm thế nào người ta có thể đặt điều này thanh lịch hơn trong Swift?

// excerpt from method that determines if dict contains key
if let _ = dict[key] {
    return true
}
else {
    return false
}

// excerpt from method that obtains first value from dict
for (_, value) in dict {
    return value
}

Bạn có thể sử dụng indexForKeynếu bạn cảm thấy nó rõ ràng và rõ ràng hơn; stackoverflow.com/a/29299943/294884
Fattie

Rất thường những gì bạn muốn về cơ bản là: cityName:String = dict["city"] ?? ""?? ""đây có nghĩa là về cơ bản "nếu không có khóa đó, hãy trả lại một khoảng trống".
Fattie

Câu trả lời:


481

Bạn không cần bất kỳ mã đặc biệt nào để làm điều này, vì đó là những gì một từ điển đã làm. Khi bạn tìm nạp, dict[key]bạn biết liệu từ điển có chứa khóa hay không, bởi vì Tùy chọn mà bạn nhận lại không phải là nil(và nó có chứa giá trị).

Vì vậy, nếu bạn chỉ muốn trả lời câu hỏi liệu từ điển có chứa khóa hay không, hãy hỏi:

let keyExists = dict[key] != nil

Nếu bạn muốn giá trị và bạn biết từ điển chứa khóa, hãy nói:

let val = dict[key]!

Nhưng nếu, như thường xảy ra, bạn không biết nó chứa khóa - bạn muốn lấy nó và sử dụng nó, nhưng chỉ khi nó tồn tại - thì hãy sử dụng cái gì đó như if let:

if let val = dict[key] {
    // now val is not nil and the Optional has been unwrapped, so use it
}

6
Tôi không làm theo. Tôi vừa đạt được một giá trị (hai lần). Nhiều hơn những gì bạn muốn?
matt

Không có thứ gọi là "giá trị đầu tiên"; một từ điển không có thứ tự Nếu bạn chỉ muốn các giá trị, không có các phím, hãy nói dict.values.
matt

1
Cẩn thận vì dict.valuesmờ đục. Bạn có thể xoay vòng nó nhưng đó là tất cả. (Được rồi, đó không phải là tất cả, nhưng hài hước cho tôi.) Nếu bạn muốn nó hợp nhất thành một Mảng, hãy lấy dict.values.array.
matt

1
@bubakazouba Hãy thử điều này: let d = ["hey":"ho"]; let s = d["hey"]; print(s)Đây là một Tùy chọn, giống như mọi khi.
matt

1
@Kross Đó là một câu hỏi rất sâu sắc nhưng do đó, vui lòng hỏi riêng.
mờ

68

Tại sao không chỉ đơn giản là kiểm tra dict.keys.contains(key)? Kiểm tra dict[key] != nilsẽ không hoạt động trong trường hợp giá trị bằng không. Như với một từ điển [String: String?]chẳng hạn.


2
Hoặc thay vì chỉ viết if let val = dict[key]bạn có thể sử dụng if let val = dict[key] as? Stringtrong trường hợp này.
Okhan Okbay

.keys.contains không giúp phân biệt liệu khóa có tồn tại hay không, nếu giá trị là 0. Có lẽ trong các phiên bản nhanh hơn trước? Không làm việc cho tôi trong swift 4.
Rowan Gontier

8
Điều này có khả năng rất lãng phí, bởi vì (1) bạn gọi dict.keysđó tạo ra một mảng với tất cả các khóa, sau đó (2) kiểm tra mọi khóa theo thứ tự cho đến khi bạn tìm thấy một (hoặc không có gì!). Tôi nhận ra rằng bạn đang cố gắng giải quyết trường hợp của a [String: String?], nhưng sẽ rất cẩn thận với giải pháp đó ...
charles

3
Như @charles đã đề cập, điều này sẽ loại bỏ lợi ích tra cứu nhanh mà việc sử dụng từ điển cung cấp vì vậy tôi khuyên bạn nên chống lại điều này, nhưng vẫn chắc chắn là một lựa chọn hợp lệ.
kinh doanh

4
Bạn không bao giờ nên sử dụng phương pháp này, trong đó có độ phức tạp O (n) thay vì lý thuyết (phụ thuộc vào việc thực hiện hàm băm) O (1) của truy cập từ điển trực tiếp.
Krypt

45

Câu trả lời được chấp nhận let keyExists = dict[key] != nilsẽ không hoạt động nếu Từ điển chứa khóa nhưng có giá trị bằng 0.

Nếu bạn muốn chắc chắn rằng Từ điển hoàn toàn không chứa khóa, hãy sử dụng cái này (đã được thử nghiệm trong Swift 4).

if dict.keys.contains(key) {
  // contains key
} else { 
  // does not contain key
}

3
Điều này giống như câu trả lời của Han.
Declan McKenna

1
Kiểm tra == nilkhông hoạt động, ngay cả khi từ điển có các giá trị tùy chọn. Điều này là do kết quả tra cứu được gói như một Optional. Mặt khác, để kiểm tra xem giá trị tra cứu có thực sự nilthay vì vắng mặt, bạn có thể sử dụng == .some(nil).
jedwidz

1
Tôi sẽ thêm hiệu quả của việc sử dụng phương pháp này so với tra cứu O (1) của các phương pháp khác. Tôi tin rằng đó là tra cứu O (n)
Alberto Vega

1
@ AlbertoVega-MSFT Đó là O(1). Xem thêm: github.com/apple/swift-evolution/blob/master/proposeals/NH Điều gì khiến bạn nghĩ đó là O(n)?
Alexander - Tái lập Monica

1
Tài liệu cho Dictionary.Keys.contains(...)hàm ở đây cho biết nó có O(n)độ phức tạp, nđộ dài của chuỗi là bao nhiêu.
Adil Hussain

5

Có vẻ như bạn đã nhận được những gì bạn cần từ @matt, nhưng nếu bạn muốn một cách nhanh chóng để lấy giá trị cho một khóa hoặc chỉ là giá trị đầu tiên nếu khóa đó không tồn tại:

extension Dictionary {
    func keyedOrFirstValue(key: Key) -> Value? {
        // if key not found, replace the nil with 
        // the first element of the values collection
        return self[key] ?? first(self.values)
        // note, this is still an optional (because the
        // dictionary could be empty)
    }
}

let d = ["one":"red", "two":"blue"]

d.keyedOrFirstValue("one")  // {Some "red"}
d.keyedOrFirstValue("two")  // {Some "blue"}
d.keyedOrFirstValue("three")  // {Some "red”}

Lưu ý, không đảm bảo những gì bạn thực sự sẽ nhận được như là giá trị đầu tiên, nó chỉ xảy ra trong trường hợp này để trả lại màu đỏ.


1
Việc sử dụng tốt ??nhà điều hành đã lấy giải pháp tiện lợi của tôi từ tôi, nhưng như một phần mở rộng mà giá trị mặc định có thể gây ra sự không an toàn dữ liệu hoặc các hành vi không mong muốn. Nghe có vẻ như một thứ gì đó mà một lớp con cụ thể Dictionarynên sử dụng. Tần suất bạn cần giá trị đầu tiên trong trường hợp niltrả lại không bao gồm chức năng cụ thể theo tình huống?
NoodleOfDeath


0

Giải pháp của tôi cho việc triển khai bộ đệm lưu trữ NSAttributionString tùy chọn:

public static var attributedMessageTextCache    = [String: NSAttributedString?]()

    if attributedMessageTextCache.index(forKey: "key") != nil
    {
        if let attributedMessageText = TextChatCache.attributedMessageTextCache["key"]
        {
            return attributedMessageText
        }
        return nil
    }

    TextChatCache.attributedMessageTextCache["key"] = .some(.none)
    return nil

0

Đây là những gì làm việc cho tôi trên Swift 3

let _ = (dict[key].map { $0 as? String } ?? "")
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.