การค้นหา <TKey, TElement> คืออะไร


155

MSDN อธิบายการค้นหาเช่นนี้:

คล้ายLookup<TKey, TElement> Dictionary<TKey, TValue>ความแตกต่างคือ พจนานุกรม <TKey, TValue>จับคู่คีย์กับค่าเดียวขณะที่การ ค้นหา <TKey, TElement>จับคู่คีย์กับชุดของค่า

ฉันไม่พบคำอธิบายที่เป็นประโยชน์โดยเฉพาะอย่างยิ่ง การค้นหาใช้สำหรับทำอะไร

คำตอบ:


215

มันเป็นความแตกต่างระหว่างIGroupingและพจนานุกรม มันช่วยให้คุณจัดกลุ่มรายการด้วยคีย์ แต่จากนั้นเข้าถึงรายการเหล่านั้นผ่านทางคีย์นั้นอย่างมีประสิทธิภาพ (ไม่ใช่แค่วนซ้ำมันทั้งหมดซึ่งเป็นสิ่งที่GroupByคุณสามารถทำได้)

ตัวอย่างเช่นคุณสามารถโหลดประเภท. NET และสร้างการค้นหาตามเนมสเปซ ... จากนั้นไปที่ประเภททั้งหมดในเนมสเปซที่เฉพาะเจาะจงได้อย่างง่ายดายมาก:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;

public class Test
{
    static void Main()
    {
        // Just types covering some different assemblies
        Type[] sampleTypes = new[] { typeof(List<>), typeof(string), 
                                     typeof(Enumerable), typeof(XmlReader) };

        // All the types in those assemblies
        IEnumerable<Type> allTypes = sampleTypes.Select(t => t.Assembly)
                                               .SelectMany(a => a.GetTypes());

        // Grouped by namespace, but indexable
        ILookup<string, Type> lookup = allTypes.ToLookup(t => t.Namespace);

        foreach (Type type in lookup["System"])
        {
            Console.WriteLine("{0}: {1}", 
                              type.FullName, type.Assembly.GetName().Name);
        }
    }
}

(โดยปกติฉันจะใช้varสำหรับการประกาศเหล่านี้ส่วนใหญ่ในรหัสปกติ)


59
ฉันคิดว่าจะทำให้คำตอบนี้ดีขึ้นคุณสามารถแทนที่ vars บางส่วนได้ เพื่อจุดประสงค์ในการเรียนรู้ฉันคิดว่ามันง่ายที่จะติดตามเมื่อแสดงประเภทอย่างชัดเจน เพียง 2 เซ็นต์ของฉัน :)
อเล็กซ์ Baranosky

3
ถ้ามันมีสิ่งที่ดีที่สุดของทั้งสองโลกทำไมต้องสนใจพจนานุกรม
Kyle Baran

15
@KyleBaran: เพราะมันจะไม่มีจุดหมายสำหรับคอลเลกชันคู่คีย์ / ค่าของแท้ซึ่งมีเพียงค่าเดียวต่อคีย์
Jon Skeet

12
@ KyleBaran Lookup<,>เป็นเพียงคอลเล็กชันที่ไม่เปลี่ยนรูปแบบ (ไม่มีAddวิธีการเช่น) ซึ่งมีการใช้งาน จำกัด ยิ่งไปกว่านั้นมันไม่ใช่การรวบรวมวัตถุประสงค์ทั่วไปในแง่ที่ว่าหากคุณค้นหาคีย์ที่ไม่มีอยู่คุณจะได้ลำดับที่ว่างเปล่าแทนที่จะเป็นข้อยกเว้นซึ่งมีความหมายเฉพาะในบริบทพิเศษเช่นด้วย linq สิ่งนี้สอดคล้องกับข้อเท็จจริงที่ว่า MS ไม่ได้จัดให้มีตัวสร้างสาธารณะสำหรับคลาส
nawfal

การอ่านคำตอบคือ jwg -> bobbymcr -> jonskeet
snr

58

วิธีหนึ่งที่จะคิดเกี่ยวกับมันอย่างนี้จะคล้ายกับLookup<TKey, TElement> Dictionary<TKey, Collection<TElement>>โดยทั่วไปรายการของศูนย์หรือมากกว่าองค์ประกอบสามารถส่งคืนผ่านทางคีย์เดียวกัน

namespace LookupSample
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    class Program
    {
        static void Main(string[] args)
        {
            List<string> names = new List<string>();
            names.Add("Smith");
            names.Add("Stevenson");
            names.Add("Jones");

            ILookup<char, string> namesByInitial = names.ToLookup((n) => n[0]);

            // count the names
            Console.WriteLine("J's: {0}", namesByInitial['J'].Count()); // 1
            Console.WriteLine("S's: {0}", namesByInitial['S'].Count()); // 2
            Console.WriteLine("Z's: {0}", namesByInitial['Z'].Count()); // 0, does not throw
        }
    }
}

2
สามารถมีองค์ประกอบเป็นศูนย์ในผลลัพธ์การค้นหาหรือไม่? คุณจะได้อย่างไร (ค้นหาจะไม่เปลี่ยนรูปสาธารณชนเท่าที่ผมสามารถบอกและผมไม่คิดว่า ToLookup มีประสิทธิภาพจะคิดค้นคีย์.)
จอนสกีต

8
ในทางเทคนิคแล้วใช่เนื่องจากการค้นหาส่งคืนคอลเลกชันที่ว่างเปล่าสำหรับคีย์ที่ไม่มีอยู่ (ฉันแก้ไขโพสต์ของฉันเพื่อเพิ่มตัวอย่างโค้ดที่แสดงสิ่งนี้)
bobbymcr

การอ่านคำตอบคือ jwg -> bobbymcr -> jonskeet
snr

คำตอบที่สะอาดและเป็นประโยชน์มากฉันหวังว่ามันจะถูกเลือก
นาทีที่

25

หนึ่งใช้อาจจะย้อนกลับLookupDictionary

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

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

dictionary["555-6593"] = "Dr. Emmett Brown";
dictionary["555-6593"] = "Marty McFly";

หมายความว่ารายการที่สองเขียนทับรายการแรก - เอกสารไม่อยู่ในรายการอีกต่อไป

พยายามเขียนข้อมูลเดียวกันด้วยวิธีที่แตกต่างกันเล็กน้อย:

dictionary.Add("555-6593", "Dr. Emmett Brown");
dictionary.Add("555-6593", "Marty McFly");

จะโยนข้อยกเว้นในบรรทัดที่สองนับตั้งแต่ที่คุณไม่สามารถที่สำคัญที่มีอยู่แล้วในAddDictionary

[แน่นอนคุณอาจต้องการที่จะใช้โครงสร้างข้อมูลเดียวอื่น ๆ ให้ค้นหาในทั้งสองทิศทาง ฯลฯ ตัวอย่างเช่นนี้หมายความว่าคุณจะต้องงอกใหม่LookupจากDictionaryทุกครั้งที่มีการเปลี่ยนแปลงหลัง แต่สำหรับข้อมูลบางอย่างมันอาจเป็นทางออกที่ถูกต้อง]


คำตอบมีความสำคัญต่อการเข้าใจแนวคิด +1 การอ่านคำตอบคือ jwg -> bobbymcr -> jonskeet
snr

15

ฉันไม่เคยใช้งานมาก่อน แต่นี่เป็นสิ่งที่ฉันต้องทำ

A Lookup<TKey, TElement>จะทำงานเหมือนดัชนีฐานข้อมูล (เชิงสัมพันธ์) บนตารางโดยไม่มีข้อ จำกัด ที่ไม่เหมือนใคร ใช้ในสถานที่เดียวกันกับที่คุณจะใช้อีก


5

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

การค้นหาจะจับคู่กับหลายค่า

การค้นหา ["สมิ ธ "] ["จอห์น"] จะเป็นคอลเล็กชั่นขนาดหนึ่งพันล้าน


คำตอบของคุณเป็นแรงบันดาลใจให้คำถามติดตามของฉัน"How ToLookup () มีดัชนีหลายตัวหรือไม่" . ฉันจะทำเช่นนี้โดยค้นหาหลายดัชนีได้อย่างไร คุณสามารถตอบโดยใช้ตัวอย่างหรือการอ้างอิงอื่น ๆ ที่เป็นไปได้ที่จะใช้ Lookup["Smith"]["John"] หรือไม่?
Fulproof
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.