Qual é o objetivo da pesquisa <TKey, TElement>?

155

O MSDN explica a Pesquisa assim:

A se Lookup<TKey, TElement> assemelha a Dictionary<TKey, TValue>. A diferença é que um Dictionary <TKey, TValue> mapeia chaves para valores únicos, enquanto uma Lookup <TKey, TElement> mapeia chaves para coleções de valores.

Não acho essa explicação particularmente útil. Para que é usada a Pesquisa?

dan-gph
fonte

Respostas:

215

É um cruzamento entre um IGroupinge um dicionário. Permite agrupar itens por uma chave, mas depois acessá-los através dessa chave de maneira eficiente (em vez de apenas iterar sobre todos eles, é isso que GroupBypermite fazer).

Por exemplo, você pode pegar uma carga de tipos .NET e criar uma pesquisa por namespace ... e acessar todos os tipos em um namespace específico com muita facilidade:

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

Normalmente, eu usaria vara maioria dessas declarações no código normal.

Jon Skeet
fonte
59
Penso que para melhorar esta resposta, você pode substituir alguns dos vars. Para fins de aprendizado, acho que é mais fácil seguir, quando os tipos são expressos claramente. Apenas meus 2 centavos :)
Alex Baranosky
3
Se ele tem o melhor dos dois mundos, por que se preocupar com um dicionário?
Kyle Baran 21/03
15
@KyleBaran: Porque seria inútil para coleções de pares de chave / valor genuínos, onde há apenas um único valor por chave.
precisa
12
O @KyleBaran Lookup<,>é simplesmente uma coleção imutável (sem Addmétodo para, por exemplo), que tem um uso limitado. Além disso, não é uma coleção de propósito geral, no sentido de que, se você pesquisar uma chave inexistente, obterá uma sequência vazia em vez de uma exceção, que é significativa apenas em contextos especiais, por exemplo, com linq. Isso vai bem com o fato de que a MS não forneceu um construtor público para a classe.
Nawfal
A ordem das respostas de leitura é jwg -> bobbymcr -> jonskeet
snr
58

Uma maneira de pensar sobre isso é: Lookup<TKey, TElement>é semelhante a Dictionary<TKey, Collection<TElement>>. Basicamente, uma lista de zero ou mais elementos pode ser retornada através da mesma chave.

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
fonte
2
Pode haver zero elementos em um resultado de pesquisa? Como você conseguiu isso? (Lookup é imutável publicamente, tanto quanto eu posso dizer, e eu não acho que ToLookup seria efetivamente inventar chaves.)
Jon Skeet
8
Tecnicamente, sim, uma vez que uma Pesquisa retorna uma coleção vazia para uma chave inexistente (editei minha postagem para adicionar um exemplo de código que mostra isso).
bobbymcr 10/09/09
A ordem das respostas de leitura é jwg -> bobbymcr -> jonskeet
snr
Uma resposta muito limpa e útil, gostaria que fosse selecionada.
mins
25

Um uso de Lookuppoderia ser reverter a Dictionary.

Suponha que você tenha uma lista telefônica implementada como um Dictionarycom vários nomes (exclusivos) como chaves, cada nome associado a um número de telefone. Mas duas pessoas com nomes diferentes podem compartilhar o mesmo número de telefone. Isso não é um problema para a Dictionary, que não se importa que duas chaves correspondam ao mesmo valor.

Agora você deseja descobrir a quem pertence um determinado número de telefone. Você constrói umLookup , adicionando tudo KeyValuePairsdo seu Dictionary, mas para trás, com o valor como chave e a chave como valor. Agora você pode consultar um número de telefone e obter uma lista de nomes de todas as pessoas cujo número de telefone é esse. Criar um Dictionarycom os mesmos dados eliminaria os dados (ou falharia, dependendo de como você o fez), já que fazer isso

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

significa que a segunda entrada substitui a primeira - o Doc não está mais listado.

Tentando escrever os mesmos dados de uma maneira ligeiramente diferente:

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

lançaria uma exceção na segunda linha, pois você não pode Adduma chave que já esteja na Dictionary.

[Obviamente, você pode querer usar alguma outra estrutura de dados única para fazer pesquisas nas duas direções, etc. Este exemplo significa que você precisa regenerar Lookupa Dictionarycada vez que ela mudar. Mas para alguns dados, pode ser a solução certa.]

jwg
fonte
A resposta é vital para compreender o conceito. +1. A ordem das respostas de leitura é jwg -> bobbymcr -> jonskeet
snr
15

Eu não o usei com sucesso antes, mas aqui está a minha chance:

A Lookup<TKey, TElement>se comportaria como um índice de banco de dados (relacional) em uma tabela sem uma restrição exclusiva. Use-o nos mesmos lugares que você usaria o outro.

Daren Thomas
fonte
5

Acho que você poderia argumentar dessa maneira: imagine que você está criando uma estrutura de dados para armazenar o conteúdo de uma lista telefônica. Você deseja digitar por sobrenome e depois por nome. Usar um dicionário aqui seria perigoso, porque muitas pessoas podem ter o mesmo nome. Portanto, um dicionário sempre será, no máximo, mapeado para um único valor.

Uma pesquisa mapeará para vários valores potencialmente.

A pesquisa ["Smith"] ["John"] será uma coleção do tamanho de um bilhão.

David Andres
fonte
Sua resposta inspirou minha pergunta de acompanhamento "Como ToLookup () com vários índices?" . Como posso reproduzir essa pesquisa com vários índices? Você poderia responder possivelmente usando outra amostra ou referência onde é possível usar Lookup["Smith"]["John"] ?
Fulproof