Swift sözlüğünün anahtar içerip içermediğini belirleme ve değerlerinden herhangi birini elde etme


260

Şu anda bir (boş olmayan) Swift sözlüğü verilen bir anahtar içerip içermediğini belirlemek ve aynı sözlükten bir (herhangi bir) değer elde etmek için aşağıdaki (beceriksiz) kod parçalarını kullanıyorum.

Swift'e bunu nasıl daha şık bir hale getirebiliriz?

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

Daha indexForKeynet ve daha açık olduğunu düşünüyorsanız kullanabilirsiniz ; stackoverflow.com/a/29299943/294884
Fattie

Çoğu zaman ne istediğinizi temelde: "Böyle bir anahtar varsa, bir boş dönmek" Burada temelde anlamına gelir. cityName:String = dict["city"] ?? ""?? ""
Fattie

Yanıtlar:


481

Buna gerek yok herhangi bir sözlüğü zaten yaptığı iştir çünkü bunu yapmak için özel bir kod. Eğer getir zaman dict[key]sen biliyorsun değil geri almak İsteğe çünkü sözlük anahtarı içerip içermediğini nil(ve değer içerir).

Eğer Yani, eğer sadece sözlük anahtarını içerip içermediğini soruya cevap vermek istiyorum, soruyorum:

let keyExists = dict[key] != nil

Değeri istiyorsanız ve sözlüğün anahtarı içerdiğini biliyorsanız şunu söyleyin:

let val = dict[key]!

Ancak, genellikle olduğu gibi, anahtarın içerdiğini bilmiyorsanız - onu almak ve kullanmak istiyorsunuz, ancak sadece varsa - o zaman şöyle bir şey kullanın if let:

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

6
Takip etmiyorum. Sadece bir değer elde ettim (iki kez). Daha fazla İstediğiniz ne?
matt

"İlk değer" diye bir şey yoktur; bir sözlük sırasız. Değerleri sadece anahtarlar olmadan istiyorsanız, söyleyin dict.values.
matt

1
Dikkatli ol çünkü dict.valuesopak. Bunu kullanarak dolaşabilirsiniz ama hepsi bu. (Tamam, hepsi değil ama beni mizah edin.) Bir Dizi ile ilişkilendirilmesini istiyorsanız, alın dict.values.array.
matt

1
@bubakazouba Şunu deneyin: let d = ["hey":"ho"]; let s = d["hey"]; print(s)Her zaman olduğu gibi isteğe bağlıdır.
matt

1
@Kross Bu çok derin bir soru ama bu yüzden lütfen ayrı olarak sorun.
matt

68

Neden sadece kontrol etmiyorsun dict.keys.contains(key)? dict[key] != nilDeğerin sıfır olduğu durumlarda denetleme çalışmaz. [String: String?]Örneğin bir sözlükte olduğu gibi.


2
Ya da sadece yazmak yerine bu durumda if let val = dict[key]kullanabilirsiniz if let val = dict[key] as? String.
Okhan Okbay

.keys.contains anahtarın var olup olmadığını veya değerin nil olup olmadığını ayırt etmeye yardımcı olmaz. Belki önceki hızlı sürümlerde? Hızlı 4'te benim için çalışmıyor
Rowan Gontier

8
Bu potansiyel olarak çok israftır, çünkü (1) dict.keystüm anahtarları içeren bir dizi oluşturur, ardından (2) birini (veya hiçbirini!) Bulana kadar her anahtarı sırayla kontrol eder. Bir davayı ele almaya çalıştığınızı anlıyorum [String: String?], ancak bu çözümle çok dikkatli olacağım ...
charles

3
@Charles belirtildiği gibi, bu bir sözlük kullanarak hızlı arama yarar ortadan kaldıracak, bu yüzden buna karşı tavsiye ediyorum, ama yine de kesinlikle geçerli bir seçenek.
businesscasual

4
Sen gerektiğini asla direkt sözlük erişimin karmaşıklığı O (n) yerine teorik (hash fonksiyonu uygulanmasına bağlıdır) O (1) vardır içinde, bu yöntemi kullanın.
Krypt

45

let keyExists = dict[key] != nilSözlük anahtar içeriyorsa ancak nil değerine sahipse, kabul edilen yanıt çalışmaz.

Sözlüğün anahtarı hiç içermediğinden emin olmak istiyorsanız bunu kullanın (Swift 4'te test edilmiştir).

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

3
Bu Han'ın cevabı ile aynı.
Declan McKenna

1
== nilSözlük isteğe bağlı değerlere sahip olsa bile kontrol çalışır. Bunun nedeni, arama sonucunun bir Optional. Öte yandan, aranan değerin gerçekten nileksik olup olmadığını kontrol etmek için kullanabilirsiniz == .some(nil).
jedwidz

1
Diğer metotların O (1) aramasına kıyasla bu metodu kullanmanın etkinliğini arttırırdım. Sanırım O (n) araması
Alberto Vega

1
@ AlbertoVega-MSFT Bu O(1). Ayrıca bakınız: github.com/apple/swift-evolution/blob/master/proposals/… Sizi bunun ne düşündürdü O(n)?
Alexander - Monica'yı eski

1
Belgeleri Dictionary.Keys.contains(...)fonksiyonu burada o diyor O(n)nerede, karmaşıklığı ndizisinin uzunluğudur.
Adil Hussain

5

Görünüşe göre @matt'dan ihtiyacınız olanı aldınız, ancak bir anahtar için değer elde etmenin hızlı bir yolunu veya bu anahtar yoksa yalnızca ilk değeri istiyorsanız:

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

Not, ilk değer olarak gerçekte ne alacağınızı garanti etmez, sadece bu durumda “kırmızı” dönmek olur.


1
??operatörün iyi kullanımı benim kolaylık çözümümü benden aldı, ancak bir uzantı olarak varsayılan değer veri güvensizlikleri veya beklenmedik davranışlar sunabilir. Bu somut bir alt sınıfın kullanılması Dictionarygereken bir şey gibi geliyor . nilDuruma özgü işlevsellik hariç bir geri dönüş durumunda ilk değere ne sıklıkta ihtiyacınız vardır ?
NoodleOfDeath


0

İsteğe bağlı NSAttributedString depolayan bir önbellek uygulaması için benim çözüm:

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

İşte Swift 3'te benim için işe yarayan

let _ = (dict[key].map { $0 as? String } ?? "")
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.