การพิจารณาว่าพจนานุกรม Swift มีคีย์และรับค่าใด ๆ ของมันหรือไม่


260

ขณะนี้ฉันกำลังใช้ชิ้นส่วนของโค้ด (ซุ่มซ่าม) ต่อไปนี้เพื่อพิจารณาว่าพจนานุกรม Swift (ไม่ว่าง) มีคีย์ที่กำหนดและเพื่อรับค่าหนึ่งค่า (ใด ๆ ) จากพจนานุกรมเดียวกัน

เราจะนำสิ่งนี้ให้สวยงามยิ่งขึ้นใน 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
}

คุณสามารถใช้indexForKeyหากคุณรู้สึกว่าชัดเจนและชัดเจนยิ่งขึ้น stackoverflow.com/a/29299943/294884
Fattie

มากมักจะสิ่งที่คุณต้องการจะเป็นพื้น: นี่หมายความว่าโดยทั่วไป "ถ้าไม่มีที่สำคัญเช่นกลับว่างเปล่า" cityName:String = dict["city"] ?? ""?? ""
Fattie

คำตอบ:


481

คุณไม่จำเป็นต้องใช้รหัสพิเศษใด ๆในการทำเช่นนี้เพราะมันเป็นสิ่งที่พจนานุกรมทำอยู่แล้ว เมื่อคุณดึงdict[key]คุณรู้ว่าพจนานุกรมมีกุญแจหรือไม่เพราะตัวเลือกที่คุณได้รับกลับมานั้นไม่ใช่nil(และมีค่าอยู่)

ดังนั้นถ้าคุณเพียงต้องการที่จะตอบคำถามว่าพจนานุกรมมีคีย์ถาม:

let keyExists = dict[key] != nil

ถ้าคุณต้องการค่าและคุณรู้ว่าพจนานุกรมมีกุญแจพูด:

let val = dict[key]!

แต่ถ้าตามปกติจะเกิดขึ้นคุณไม่ทราบว่ามันมีรหัส - คุณต้องการดึงข้อมูลและใช้มัน แต่ถ้ามีอยู่ - ให้ใช้สิ่งที่ต้องการif let:

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

6
ฉันไม่ทำตาม ฉันเพิ่งได้รับค่า (สองครั้ง) คุณต้องการอะไรอีก
แมตต์

ไม่มีสิ่งเช่น "ค่าแรก"; ไม่มีการเรียงลำดับพจนานุกรม dict.valuesถ้าคุณเพียงต้องการค่าโดยไม่ต้องคีย์พูด
matt

1
ระวังเพราะdict.valuesทึบ คุณสามารถวนผ่านได้ แต่นั่นคือทั้งหมด (เอาล่ะจะไม่ทั้งหมด แต่อารมณ์ขันฉัน.) หากคุณต้องการที่จะ reified dict.values.arrayอาร์เรย์ใช้
แมตต์

1
@bubakazouba ลองนี้: let d = ["hey":"ho"]; let s = d["hey"]; print(s)มันเป็นตัวเลือกเหมือนกับที่เคยเป็นมา
matt

1
@ Kross นั่นเป็นคำถามที่ลึกซึ้งมาก แต่โปรดถามแยกต่างหาก
แมตต์

68

ทำไมไม่เพียงตรวจสอบdict.keys.contains(key)? การตรวจสอบdict[key] != nilจะไม่ทำงานในกรณีที่ค่าเป็นศูนย์ เช่นเดียวกับพจนานุกรม[String: String?]เช่น


2
หรือแทนที่จะเขียนเพียงแค่if let val = dict[key]คุณสามารถใช้if let val = dict[key] as? Stringในกรณีนี้
Okhan Okbay

.keys.contain ไม่ช่วยแยกแยะว่ามีกุญแจอยู่หรือไม่ถ้าค่าเป็นศูนย์ อาจจะเป็นรุ่นที่รวดเร็วก่อนหน้า? ใช้งานไม่ได้กับฉันอย่างรวดเร็ว 4
Rowan Gontier

8
สิ่งนี้อาจสิ้นเปลืองมากเพราะ (1) คุณเรียกdict.keysที่สร้างอาร์เรย์พร้อมกับคีย์ทั้งหมดจากนั้น (2) ตรวจสอบทุกคีย์ตามลำดับจนกว่าคุณจะพบหนึ่ง (หรือไม่มี!) ฉันรู้ว่าคุณกำลังพยายามที่จะอยู่ที่กรณีของการให้[String: String?]แต่จะระมัดระวังกับการแก้ปัญหาที่ ...
ชาร์ลส์

3
ดังที่ @charles กล่าวถึงสิ่งนี้จะช่วยลดผลประโยชน์การค้นหาอย่างรวดเร็วที่การใช้พจนานุกรมมอบให้ดังนั้นฉันจึงแนะนำให้เทียบกับสิ่งนี้ แต่ยังคงเป็นตัวเลือกที่ถูกต้อง
businesscasual

4
คุณไม่ควรใช้วิธีนี้เนื่องจากมีความซับซ้อน O (n) แทนที่จะเป็นเชิงทฤษฎี (ขึ้นอยู่กับการใช้ฟังก์ชั่นแฮช) O (1) ของการเข้าถึงพจนานุกรมโดยตรง
Krypt

45

คำตอบที่ยอมรับlet keyExists = dict[key] != nilจะไม่ทำงานหากพจนานุกรมมีคีย์ แต่มีค่าเป็นศูนย์

หากคุณต้องการแน่ใจว่าพจนานุกรมไม่มีคีย์เลยใช้สิ่งนี้ (ทดสอบใน Swift 4)

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

3
นี่เป็นคำตอบเดียวกับฮัน
Declan McKenna

1
การตรวจสอบ== nilใช้งานได้แม้ว่าพจนานุกรมจะมีค่าเพิ่มเติม Optionalเพราะนี่คือผลการค้นหาเป็นห่อเป็น บนมืออื่น ๆ เพื่อตรวจสอบถ้ามองขึ้นค่ามันมากกว่าขาดคุณสามารถใช้nil == .some(nil)
jedwidz

1
ฉันจะเพิ่มประสิทธิภาพของการใช้วิธีนี้เทียบกับ O (1) การค้นหาของวิธีอื่น ฉันเชื่อว่ามันเป็นการค้นหา O (n)
Alberto Vega

1
@ AlbertoVega-MSFT O(1)มัน ดูเพิ่มเติมที่: github.com/apple/swift-evolution/blob/master/proposals/ ......อะไรที่ทำให้คุณคิดว่ามันคือO(n)อะไร?
Alexander - Reinstate Monica

1
เอกสารสำหรับDictionary.Keys.contains(...)ฟังก์ชั่นที่นี่บอกว่ามันมีO(n)ความซับซ้อนซึ่งnเป็นความยาวของลำดับ
Adil Hussain

5

ดูเหมือนว่าคุณจะได้รับสิ่งที่คุณต้องการจาก @matt แต่ถ้าคุณต้องการวิธีที่รวดเร็วในการรับค่าของคีย์หรือเพียงแค่ค่าแรกถ้าไม่มีคีย์นั้น:

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

หมายเหตุไม่รับประกันสิ่งที่คุณจะได้รับเป็นค่าแรกมันเกิดขึ้นในกรณีนี้เพื่อส่งคืน "สีแดง"


1
การใช้งานที่ดีของ??ผู้ปฏิบัติงานใช้วิธีแก้ปัญหาความสะดวกสบายของฉันจากฉัน แต่เป็นส่วนขยายที่ค่าเริ่มต้นสามารถนำเสนอความไม่มั่นคงของข้อมูลหรือพฤติกรรมที่ไม่คาดคิด นั่นฟังดูเป็นสิ่งที่เป็นรูปธรรมรองDictionaryควรจะจ้าง คุณต้องการค่าแรกในกรณีที่มีการnilส่งคืนซึ่งไม่รวมฟังก์ชันการทำงานเฉพาะของสถานการณ์บ่อยเพียงใด
NoodleOfDeath


0

โซลูชันของฉันสำหรับการใช้แคชที่เก็บ NSAttributedString ทางเลือก:

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.