Điểm Tra cứu <TKey, TEuity> là gì?


155

MSDN giải thích Tra cứu như thế này:

A Lookup<TKey, TElement> giống a Dictionary<TKey, TValue>. Sự khác biệt là từ điển <TKey, TValue> ánh xạ các khóa thành các giá trị đơn, trong khi Tra cứu <TKey, TEuity> ánh xạ các khóa vào bộ sưu tập các giá trị.

Tôi không thấy lời giải thích đó đặc biệt hữu ích. Tra cứu được sử dụng để làm gì?

Câu trả lời:


215

Đó là một giao thoa giữa một IGroupingvà một từ điển. Nó cho phép bạn nhóm các mục lại với nhau bằng một khóa, nhưng sau đó truy cập chúng qua khóa đó một cách hiệu quả (thay vì chỉ lặp lại tất cả chúng, đó là những gì GroupBycho phép bạn làm).

Ví dụ: bạn có thể tải các loại .NET và xây dựng tra cứu theo không gian tên ... sau đó dễ dàng truy cập tất cả các loại trong một không gian tên cụ thể:

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

(Tôi thường sử dụng varcho hầu hết các khai báo này, theo mã thông thường.)


59
Tôi nghĩ rằng để làm cho câu trả lời này tốt hơn, bạn có thể thay thế một số vars. Đối với mục đích học tập tôi nghĩ rằng nó dễ theo dõi hơn, khi các loại được thể hiện rõ ràng. Chỉ 2 xu của tôi :)
Alex Baranosky

3
Nếu nó có thứ tốt nhất của cả hai thế giới, vậy thì tại sao phải bận tâm với một cuốn Từ điển?
Kyle Baran

15
@KyleBaran: Bởi vì sẽ vô nghĩa đối với các bộ sưu tập cặp khóa / giá trị chính hãng, nơi chỉ có một giá trị duy nhất cho mỗi khóa.
Jon Skeet

12
@KyleBaran Lookup<,>chỉ đơn giản là một bộ sưu tập bất biến (không có Addphương pháp nào, ví dụ) có hạn sử dụng. Hơn nữa, nó không phải là một bộ sưu tập mục đích chung theo nghĩa là nếu bạn tìm kiếm một khóa không tồn tại, bạn sẽ nhận được một chuỗi trống chứ không phải là một ngoại lệ, chỉ có ý nghĩa trong bối cảnh đặc biệt, ví dụ, với linq. Điều này phù hợp với thực tế là MS đã không cung cấp một hàm tạo công khai cho lớp.
nawfal

Thứ tự đọc câu trả lời là jwg -> bobbymcr -> jonskeet
snr

58

Một cách để nghĩ về nó là thế này: Lookup<TKey, TElement>tương tự như Dictionary<TKey, Collection<TElement>>. Về cơ bản, một danh sách gồm 0 hoặc nhiều phần tử có thể được trả về qua cùng một khóa.

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
Có thể có các yếu tố không trong một kết quả tra cứu? Làm thế nào bạn sẽ có được điều đó? (Tra cứu là bất biến công khai theo như tôi có thể nói, và tôi không nghĩ ToLookup sẽ phát minh ra các khóa một cách hiệu quả.)
Jon Skeet

8
Về mặt kỹ thuật, vâng, vì Tra cứu trả về một bộ sưu tập trống cho khóa không tồn tại (Tôi đã chỉnh sửa bài đăng của mình để thêm một mẫu mã cho thấy điều này).
bobbymcr

Thứ tự đọc câu trả lời là jwg -> bobbymcr -> jonskeet
snr

Một câu trả lời rất sạch sẽ và hữu ích, tôi muốn nó được chọn.
phút

25

Một cách sử dụng Lookupcó thể là đảo ngược a Dictionary.

Giả sử bạn có một danh bạ được triển khai dưới dạng một Dictionaryloạt các tên (duy nhất) làm khóa, mỗi tên được liên kết với một số điện thoại. Nhưng hai người có tên khác nhau có thể chia sẻ cùng một số điện thoại. Đây không phải là vấn đề đối với a Dictionary, điều này không quan tâm đến việc hai khóa tương ứng với cùng một giá trị.

Bây giờ bạn muốn có một cách tìm kiếm một số điện thoại nhất định thuộc về ai. Bạn xây dựng một Lookup, thêm tất cả KeyValuePairstừ của bạn Dictionary, nhưng ngược lại, với giá trị là khóa và khóa là giá trị. Bây giờ bạn có thể truy vấn một số điện thoại và có được một danh sách tên của tất cả những người có số điện thoại đó. Xây dựng một Dictionarydữ liệu giống nhau sẽ làm mất dữ liệu (hoặc thất bại, tùy thuộc vào cách bạn đã thực hiện), kể từ khi thực hiện

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

có nghĩa là mục thứ hai ghi đè lên mục thứ nhất - Tài liệu không còn được liệt kê.

Cố gắng viết cùng một dữ liệu theo một cách hơi khác:

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

sẽ ném một ngoại lệ trên dòng thứ hai vì bạn không thể Addlà một khóa đã có trong Dictionary.

[Tất nhiên, bạn có thể muốn sử dụng một số cấu trúc dữ liệu đơn lẻ khác để thực hiện tra cứu theo cả hai hướng, v.v. Ví dụ này có nghĩa là bạn phải tạo lại Lookuptừ Dictionarymỗi lần thay đổi sau. Nhưng đối với một số dữ liệu, nó có thể là giải pháp phù hợp.]


Câu trả lời là rất quan trọng để hiểu khái niệm. +1. Thứ tự đọc câu trả lời là jwg -> bobbymcr -> jonskeet
snr

15

Tôi chưa từng sử dụng thành công trước đây, nhưng đây là cách của tôi:

Một Lookup<TKey, TElement>hành vi sẽ khá giống như một chỉ mục cơ sở dữ liệu (quan hệ) trên một bảng mà không có một ràng buộc duy nhất. Sử dụng nó ở cùng một nơi bạn sẽ sử dụng khác.


5

Tôi đoán bạn có thể tranh luận theo cách này: hãy tưởng tượng bạn đang tạo cấu trúc dữ liệu để chứa nội dung của một danh bạ điện thoại. Bạn muốn nhập bằng LastName và sau đó bằng FirstName. Sử dụng từ điển ở đây sẽ nguy hiểm vì nhiều người có thể có cùng tên. Vì vậy, một từ điển sẽ luôn luôn, tối đa, ánh xạ tới một giá trị duy nhất.

Một Tra cứu sẽ ánh xạ tới một số giá trị.

Tra cứu ["Smith"] ["John"] sẽ là một bộ sưu tập có kích thước một tỷ.


Câu trả lời của bạn đã truyền cảm hứng cho câu hỏi tiếp theo của tôi "Làm thế nào ToLookup () với nhiều chỉ mục?" . Làm thế nào tôi có thể sao chép như vậy, với nhiều chỉ mục, tra cứu? Bạn có thể trả lời nó có thể sử dụng bất kỳ mẫu hoặc tài liệu tham khảo nào khác khi có thể sử dụng Lookup["Smith"]["John"] không?
Fulproof
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.