¿Cuál es el punto de búsqueda <TKey, TElement>?

155

El MSDN explica una búsqueda como esta:

A se Lookup<TKey, TElement> asemeja a a Dictionary<TKey, TValue>. La diferencia es que un Dictionary <TKey, TValue> asigna claves a valores individuales, mientras que un Lookup <TKey, TElement> asigna claves a colecciones de valores.

No encuentro esa explicación particularmente útil. ¿Para qué se utiliza la búsqueda?

dan-gph
fuente

Respuestas:

215

Es un cruce entre an IGroupingy un diccionario. Le permite agrupar elementos por una clave, pero luego acceder a ellos a través de esa clave de manera eficiente (en lugar de simplemente iterar sobre todos ellos, que es lo que le GroupBypermite hacer).

Por ejemplo, podría tomar una carga de tipos .NET y crear una búsqueda por espacio de nombres ... luego acceder a todos los tipos en un espacio de nombres en particular muy fácilmente:

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 lo usaría varpara la mayoría de estas declaraciones, en código normal).

Jon Skeet
fuente
59
Creo que para mejorar esta respuesta, podría reemplazar algunos de los vars. Para fines de aprendizaje, creo que es más fácil de seguir, cuando los tipos se expresan claramente. Just my 2 cents :)
Alex Baranosky
3
Si tiene lo mejor de ambos mundos, ¿por qué molestarse con un diccionario?
Kyle Baran
15
@KyleBaran: Porque no tendría sentido para colecciones de pares de clave / valor genuinos, donde solo hay un valor por clave.
Jon Skeet
12
@KyleBaran Lookup<,>es simplemente una colección inmutable (sin Addmétodo, por ejemplo) que tiene un uso limitado. Además, no es una colección de propósito general en el sentido de que si busca una clave inexistente, obtiene una secuencia vacía en lugar de una excepción, que solo tiene sentido en contextos especiales, por ejemplo, con linq. Esto va bien con el hecho de que MS no ha proporcionado un constructor público para la clase.
nawfal
El orden de las respuestas de lectura es jwg -> bobbymcr -> jonskeet
snr
58

Una forma de pensarlo es esta: Lookup<TKey, TElement>es similar a Dictionary<TKey, Collection<TElement>>. Básicamente, se puede devolver una lista de cero o más elementos a través de la misma clave.

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
fuente
2
¿Puede haber cero elementos en un resultado de búsqueda? ¿Cómo conseguirías eso? (Búsqueda es inmutable públicamente por lo que yo puedo decir, y no creo ToLookup inventaría efectivamente llaves.)
Jon Skeet
8
Técnicamente, sí, ya que una búsqueda devuelve una colección vacía para una clave inexistente (edité mi publicación para agregar una muestra de código que muestra esto).
bobbymcr
El orden de las respuestas de lectura es jwg -> bobbymcr -> jonskeet
snr
Una respuesta muy limpia y útil, desearía que fuera seleccionada.
minutos
25

Un uso de Lookuppodría ser revertir a Dictionary.

Suponga que tiene una agenda telefónica implementada como un Dictionarycon un montón de nombres (únicos) como claves, cada nombre asociado con un número de teléfono. Pero dos personas con nombres diferentes pueden compartir el mismo número de teléfono. Esto no es un problema para a Dictionary, que no le importa que dos claves correspondan al mismo valor.

Ahora desea una forma de buscar a quién pertenece un número de teléfono determinado. Construye un Lookup, agregando todo KeyValuePairsde su Dictionary, pero al revés, con el valor como clave y la clave como valor. Ahora puede consultar un número de teléfono y obtener una lista de nombres de todas las personas cuyo número de teléfono es ese. Construir un archivo Dictionarycon los mismos datos los eliminaría (o fallaría, dependiendo de cómo lo hiciera), ya

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

significa que la segunda entrada sobrescribe la primera; el Doc ya no aparece en la lista.

Intentando escribir los mismos datos de una manera ligeramente diferente:

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

arrojaría una excepción en la segunda línea ya que no puede Adduna clave que ya está en el Dictionary.

[Por supuesto, es posible que desee utilizar alguna otra estructura de datos única para realizar búsquedas en ambas direcciones, etc. Este ejemplo significa que tiene que regenerar el Lookupde Dictionarycada vez que este último cambia. Pero para algunos datos podría ser la solución correcta.]

jwg
fuente
La respuesta es vital para comprender el concepto. +1. El orden de las respuestas de lectura es jwg -> bobbymcr -> jonskeet
snr
15

No lo he usado con éxito antes, pero aquí está mi ir:

A Lookup<TKey, TElement>se comportaría más o menos como un índice de base de datos (relacional) en una tabla sin una restricción única. Úselo en los mismos lugares donde usaría el otro.

Daren Thomas
fuente
5

Creo que podría argumentarlo de esta manera: imagine que está creando una estructura de datos para contener el contenido de una guía telefónica. Desea escribir por apellido y luego por nombre. Usar un diccionario aquí sería peligroso porque muchas personas pueden tener el mismo nombre. Por lo tanto, un Diccionario siempre, como máximo, se asignará a un solo valor.

Una búsqueda se asignará a potencialmente varios valores.

La búsqueda ["Smith"] ["John"] será una colección de tamaño mil millones.

David Andres
fuente
Su respuesta inspiró mi pregunta de seguimiento "¿Cómo buscar () con múltiples índices?" . ¿Cómo puedo reproducir tal, con múltiples índices, búsqueda? ¿Podría responder posiblemente usando cualquier otra muestra o referencia donde sea posible usar Lookup["Smith"]["John"] ?
Fulproof 01 de