ความแตกต่างระหว่างการค้นหา () และพจนานุกรม (จากรายการ ())


165

ฉันพยายามคาดศีรษะว่าโครงสร้างข้อมูลใดที่มีประสิทธิภาพมากที่สุดและเมื่อใด / ที่ไหนที่จะใช้อันไหน

ตอนนี้อาจเป็นได้ว่าฉันแค่ไม่เข้าใจโครงสร้างที่ดีพอ แต่ILookup(of key, ...)แตกต่างจากDictionary(of key, list(of ...))อย่างไร

นอกจากนี้ฉันจะต้องใช้ที่ใดILookupและจะมีประสิทธิภาพมากขึ้นในแง่ของความเร็วของโปรแกรม / หน่วยความจำ / การเข้าถึงข้อมูล ฯลฯ


1
หนึ่งอาจต้องการเห็นสิ่งที่เป็นจุด - ของ - lookuptkey - telement
nawfal

คำตอบ:


255

ความแตกต่างที่สำคัญสองประการ:

  • Lookupไม่เปลี่ยนรูป Yay :) (อย่างน้อยฉันก็เชื่อว่าLookupคลาสรูปธรรมนั้นไม่เปลี่ยนรูปและILookupอินเทอร์เฟซไม่ได้ให้สมาชิกกลายพันธุ์ใดๆ แน่นอนอาจมีการใช้งานที่ไม่แน่นอนอื่น ๆ ได้แน่นอน)
  • KeyNotFoundExceptionเมื่อคุณค้นหาที่สำคัญซึ่งไม่ได้อยู่ในการค้นหาคุณจะได้รับลำดับที่ว่างเปล่ากลับมาแทน (ดังนั้นไม่มีTryGetValueAFAICR)

พวกมันน่าจะมีประสิทธิภาพเทียบเท่ากัน - การค้นหาอาจใช้Dictionary<TKey, GroupingImplementation<TValue>>ฉากหลังได้ดี เลือกระหว่างพวกเขาตามความต้องการของคุณ โดยส่วนตัวแล้วฉันพบว่าการค้นหามักจะเหมาะสมดีกว่าDictionary<TKey, List<TValue>>ส่วนใหญ่เนื่องจากสองจุดแรกข้างต้น

โปรดทราบว่าในฐานะที่เป็นรายละเอียดการดำเนินการการดำเนินงานที่เป็นรูปธรรมของการIGrouping<,>ที่จะใช้สำหรับการดำเนินการค่าIList<TValue>ซึ่งหมายความว่ามันเป็นที่มีประสิทธิภาพที่จะใช้กับCount(), ElementAt()ฯลฯ


หากการค้นหาคีย์ที่ไม่มีอยู่ส่งผลให้เกิดลำดับที่ว่างเปล่าแทนที่จะเป็นข้อยกเว้นก็จะไม่สามารถใช้เป็นคอลเล็กชันวัตถุประสงค์ทั่วไปได้ มันก็โอเคในกรณีของคอลเลกชันที่ไม่เปลี่ยนรูปซึ่งเป็นผลพลอยได้จากการสอบถาม linq
nawfal

@nawfal - นั่นคือสิ่งที่การค้นหาเหมาะสำหรับ จากmsdn : "คุณสามารถสร้างอินสแตนซ์ของการค้นหา <TKey, TElement> โดยการเรียก ToLookup บนวัตถุที่ใช้ IEnumerable <T>
Niall Connaughton

50

น่าสนใจที่ไม่มีใครได้บอกถึงความแตกต่างที่ใหญ่ที่สุด (ถ่ายโดยตรงจากMSDN ):

การค้นหาคล้ายกับพจนานุกรม ความแตกต่างคือพจนานุกรมแมปคีย์กับค่าเดียวในขณะที่คีย์แมปการค้นหากับคอลเลกชันของค่า


51
ตรวจสอบคำถาม: มันเกี่ยวกับความแตกต่างระหว่างการค้นหา <TKey, TValue> และพจนานุกรม <TKey, List <TValue>> เพื่อให้ความแตกต่างนั้นชัดเจนอยู่แล้ว
Martao

5
@Martao บางคนพบคำถามนี้เมื่อ googling เข้าใจความแตกต่างระหว่างการค้นหาและพจนานุกรม คำตอบนี้มีประโยชน์จริงๆ
jakubiszon

34

ทั้ง a Dictionary<Key, List<Value>>และLookup<Key, Value>logically สามารถเก็บข้อมูลที่ถูกจัดระเบียบในลักษณะที่คล้ายกันและทั้งสองอย่างมีประสิทธิภาพเท่ากัน ความแตกต่างที่สำคัญคือ a Lookupไม่เปลี่ยนรูป: มันไม่มีAdd()วิธีการและไม่มีตัวสร้างสาธารณะ (และตามที่จอนพูดถึงคุณสามารถค้นหาคีย์ที่ไม่มีอยู่ได้โดยไม่มีข้อยกเว้นและมีคีย์เป็นส่วนหนึ่งของการจัดกลุ่ม)

ตามที่คุณใช้มันขึ้นอยู่กับว่าคุณต้องการใช้มันอย่างไร หากคุณยังคงรักษาแผนที่ของคีย์เป็นค่าหลายค่าที่มีการปรับเปลี่ยนอยู่ตลอดเวลาดังนั้น a Dictionary<Key, List<Value>>น่าจะดีกว่าเพราะมันไม่แน่นอน

อย่างไรก็ตามหากคุณมีลำดับของข้อมูลและเพียงต้องการมุมมองแบบอ่านอย่างเดียวของข้อมูลที่จัดเรียงโดยคีย์การค้นหานั้นง่ายมากในการสร้างและจะให้สแน็ปช็อตแบบอ่านอย่างเดียว


11

ความแตกต่างหลักระหว่างILookup<K,V>a และ a Dictionary<K, List<V>>คือพจนานุกรมไม่แน่นอน คุณสามารถเพิ่มหรือลบคีย์และเพิ่มหรือลบรายการออกจากรายการที่ค้นหาได้ ILookupคือไม่เปลี่ยนรูปและไม่สามารถแก้ไขได้ในครั้งเดียวที่สร้างขึ้น

การนำพื้นฐานของกลไกทั้งสองไปใช้จะเหมือนหรือคล้ายคลึงกันดังนั้นความเร็วในการค้นหาและรอยเท้าหน่วยความจำจะเท่ากัน


1
@JohnBustos ในแง่ของประสิทธิภาพหมายเลข มันเป็นตรรกะอย่างหมดจด คุณสามารถส่งต่อการอ้างอิงไปยังโครงสร้างโดยไม่ต้องกังวลกับคนอื่นที่แก้ไขมันจากคุณ คุณสามารถตั้งสมมติฐานเกี่ยวกับความจริงที่ว่ามันไม่เปลี่ยนรูปแบบที่คุณทำไม่ได้ถ้ามันไม่แน่นอน
Servy

ขอบคุณ Servy นั่นเป็นจุดที่ดีมากเมื่อคุณผ่านตัวแปรมากมาย ByRef บ่อย - อย่างน้อยสิ่งนี้คุณแน่ใจว่าไม่สามารถแก้ไขได้ ขอบคุณ!
John Bustos

2
@JohnBustos โปรดจำไว้ว่าวิธีการเริ่มต้นของการส่งผ่านพารามิเตอร์วิธีคือค่าคุณต้องเพิ่ม byref อย่างชัดเจนและนั่นเป็นสิ่งที่ควรทำค่อนข้างบ่อย โครงสร้างข้อมูลเหล่านี้เป็นคลาสซึ่งทำให้เป็นประเภทอ้างอิงดังนั้นการส่งผ่านค่าคือค่าของการอ้างอิงซึ่งเป็นสาเหตุที่ส่งผ่านไปยังวิธีอื่นอาจทำให้เกิดการเปลี่ยนแปลงที่มองเห็นได้กับผู้โทร
Servy

ขอบคุณ Servy ที่เปิดเวิร์มใหม่ทั้งหมดสำหรับฉันในแง่ของสิ่งที่ฉันทำ :) แต่ฉันเข้าใจสิ่งที่คุณพูด ขอบคุณ !!
John Bustos

คุณรู้หรือไม่ว่าภายใต้ที่กำบังถ้าการค้นหาใช้ hashbuckets สำหรับกุญแจ?
paparazzo

10

ข้อแตกต่างอื่นที่ไม่ได้กล่าวถึงคือ Lookup () รองรับคีย์ว่าง :

คลาสการค้นหาใช้อินเทอร์เฟซ ILookup การค้นหาคล้ายกับพจนานุกรมยกเว้นค่าหลายค่าได้รับอนุญาตให้แมปไปยังคีย์เดียวกันและรองรับคีย์ null


4

เมื่อไม่มีข้อยกเว้นให้ไปที่ค้นหา

หากคุณพยายามที่จะทำให้โครงสร้างมีประสิทธิภาพDictionaryแต่คุณไม่ทราบแน่ชัดว่าไม่มีคีย์ที่ซ้ำกันในอินพุตLookupนั้นปลอดภัยกว่า

ดังที่ได้กล่าวไว้ในคำตอบอื่นมันยังรองรับปุ่ม null และส่งคืนผลลัพธ์ที่ถูกต้องเสมอเมื่อถูกถามด้วยข้อมูลที่กำหนดเองดังนั้นจึงดูเหมือนว่ามีความยืดหยุ่นมากกว่าอินพุตที่ไม่รู้จัก (มีแนวโน้มน้อยกว่าพจนานุกรมเพื่อยกระดับข้อยกเว้น)

และมันเป็นเรื่องจริงโดยเฉพาะถ้าคุณเปรียบเทียบกับSystem.Linq.Enumerable.ToDictionaryฟังก์ชั่น:

// won't throw
new[] { 1, 1 }.ToLookup(x => x); 

// System.ArgumentException: An item with the same key has already been added.
new[] { 1, 1 }.ToDictionary(x => x);

ทางเลือกอื่นคือการเขียนรหัสการจัดการคีย์ซ้ำภายในforeachลูป

ข้อพิจารณาด้านประสิทธิภาพพจนานุกรม: ผู้ชนะที่ชัดเจน

หากคุณไม่ต้องการรายการและคุณจะจัดการรายการจำนวนมากDictionary(หรือแม้แต่โครงสร้างที่ปรับแต่งเองของคุณเอง) จะมีประสิทธิภาพมากขึ้น:

        Stopwatch stopwatch = new Stopwatch();
        var list = new List<string>();
        for (int i = 0; i < 5000000; ++i)
        {
            list.Add(i.ToString());
        }
        stopwatch.Start();
        var lookup = list.ToLookup(x => x);
        stopwatch.Stop();
        Console.WriteLine("Creation: " + stopwatch.Elapsed);

        // ... Same but for ToDictionary
        var lookup = list.ToDictionary(x => x);
        // ...

เช่นเดียวLookupกับที่ต้องรักษารายการของแต่ละคีย์มันจะช้ากว่า Dictionary (ประมาณ 3x ช้ากว่าสำหรับรายการจำนวนมาก)

ความเร็วในการค้นหา: การสร้าง: 00: 00: 01.5760444

ความเร็วพจนานุกรม: การสร้าง: 00: 00: 00.4418833

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