Apa gunanya Lookup <TKey, TElement>?

155

MSDN menjelaskan pencarian seperti ini:

A Lookup<TKey, TElement> menyerupai a Dictionary<TKey, TValue>. Perbedaannya adalah bahwa Kamus <TKey, TValue> memetakan kunci untuk nilai tunggal, sedangkan Pencarian <TKey, TElement> memetakan kunci untuk koleksi nilai.

Saya tidak menemukan penjelasan yang sangat membantu. Untuk apa Lookup digunakan?

dan-gph
sumber

Jawaban:

215

Ini adalah persilangan antara IGroupingdan kamus. Ini memungkinkan Anda mengelompokkan item bersama dengan kunci, tetapi kemudian mengaksesnya melalui kunci itu dengan cara yang efisien (bukan hanya iterasi atas semuanya, yang GroupBymemungkinkan Anda melakukannya).

Sebagai contoh, Anda dapat mengambil banyak jenis .NET dan membangun pencarian berdasarkan namespace ... kemudian mendapatkan semua jenis dalam namespace tertentu dengan sangat mudah:

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);
        }
    }
}

(Saya biasanya menggunakan varsebagian besar deklarasi ini, dalam kode normal.)

Jon Skeet
sumber
59
Saya pikir untuk membuat jawaban ini lebih baik Anda bisa mengganti beberapa vars. Untuk tujuan belajar, saya pikir lebih mudah diikuti, ketika tipe-tipe itu diungkapkan dengan jelas. Hanya 2 sen saya :)
Alex Baranosky
3
Jika memiliki yang terbaik dari kedua dunia, lalu mengapa repot-repot dengan Kamus?
Kyle Baran
15
@KyleBaran: Karena tidak ada gunanya untuk koleksi pasangan kunci / nilai asli, di mana hanya ada satu nilai per kunci.
Jon Skeet
12
@KyleBaran Lookup<,>hanyalah koleksi abadi (tanpa Addmetode misalnya) yang memiliki penggunaan terbatas. Selain itu, ini bukan kumpulan tujuan umum dalam arti bahwa jika Anda mencari pada kunci yang tidak ada Anda mendapatkan urutan kosong daripada pengecualian, yang hanya bermakna dalam konteks khusus, misalnya, dengan linq. Ini sejalan dengan fakta bahwa MS belum menyediakan konstruktor publik untuk kelas tersebut.
nawfal
Membaca rangka jawaban adalah JWG -> bobbymcr -> jonskeet
SNR
58

Salah satu cara untuk memikirkannya adalah ini: Lookup<TKey, TElement>mirip dengan Dictionary<TKey, Collection<TElement>>. Pada dasarnya daftar elemen nol atau lebih dapat dikembalikan melalui kunci yang sama.

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
        }
    }
}
bobbymcr
sumber
2
Bisakah ada nol elemen dalam hasil pencarian? Bagaimana Anda mendapatkannya? (Lookup adalah kekal publik sejauh yang saya tahu, dan saya tidak berpikir ToLookup efektif akan menciptakan kunci.)
Jon Skeet
8
Secara teknis, ya, karena Pencarian mengembalikan koleksi kosong untuk kunci yang tidak ada (saya mengedit posting saya untuk menambahkan sampel kode yang menunjukkan ini).
bobbymcr
Membaca rangka jawaban adalah JWG -> bobbymcr -> jonskeet
SNR
Jawaban yang sangat bersih dan bermanfaat, saya harap itu dipilih.
mnt
25

Salah satu penggunaan Lookupbisa untuk membalikkan a Dictionary.

Misalkan Anda memiliki buku telepon yang diimplementasikan sebagai Dictionarydengan sekelompok (unik) nama sebagai kunci, masing-masing nama yang terkait dengan nomor telepon. Tetapi dua orang dengan nama berbeda mungkin berbagi nomor telepon yang sama. Ini bukan masalah untuk a Dictionary, yang tidak peduli bahwa dua kunci sesuai dengan nilai yang sama.

Sekarang Anda ingin cara mencari tahu milik siapa nomor telepon tertentu. Anda membangun Lookup, menambahkan semua KeyValuePairsdari Anda Dictionary, tetapi mundur, dengan nilai sebagai kunci dan kunci sebagai nilai. Anda sekarang dapat meminta nomor telepon, dan mendapatkan daftar nama semua orang yang memiliki nomor telepon itu. Membangun Dictionarydengan data yang sama akan menghapus data (atau gagal, tergantung bagaimana Anda melakukannya), sejak melakukannya

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

berarti bahwa entri kedua menimpa yang pertama - Doc tidak lagi terdaftar.

Mencoba menulis data yang sama dengan cara yang sedikit berbeda:

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

akan melemparkan pengecualian pada baris kedua karena Anda tidak dapat Addkunci yang sudah ada di Dictionary.

[Tentu saja, Anda mungkin ingin menggunakan beberapa struktur data tunggal untuk melakukan pencarian di kedua arah, dll. Contoh ini berarti bahwa Anda harus membuat ulang Lookupdari Dictionarysetiap kali perubahan terakhir. Tetapi untuk beberapa data itu bisa menjadi solusi yang tepat.]

jwg
sumber
Jawabannya sangat penting untuk memahami konsep tersebut. +1. Membaca rangka jawaban adalah JWG -> bobbymcr -> jonskeet
SNR
15

Saya belum berhasil menggunakannya sebelumnya, tapi ini dia:

A Lookup<TKey, TElement>akan berperilaku seperti indeks basis data (relasional) di atas meja tanpa kendala yang unik. Gunakan di tempat yang sama dengan yang lain.

Daren Thomas
sumber
5

Saya kira Anda bisa berdebat seperti ini: bayangkan Anda sedang membuat struktur data untuk menyimpan konten buku telepon. Anda ingin memasukkan oleh lastName dan kemudian oleh firstName. Menggunakan kamus di sini akan berbahaya karena banyak orang dapat memiliki nama yang sama. Jadi Kamus akan selalu, paling banyak, memetakan ke nilai tunggal.

Pencarian akan memetakan ke beberapa nilai yang berpotensi.

Pencarian ["Smith"] ["John"] akan menjadi koleksi ukuran satu miliar.

David Andres
sumber
Jawaban Anda mengilhami pertanyaan tindak lanjut saya "Bagaimana ToLookup () dengan beberapa indeks?" . Bagaimana saya bisa mereproduksi seperti itu, dengan beberapa indeks, pencarian? Bisakah Anda menjawabnya mungkin menggunakan sampel atau referensi lain di mana dimungkinkan untuk digunakan Lookup["Smith"]["John"] ?
Fulproof