Quel est l'intérêt de Lookup <TKey, TElement>?

155

Le MSDN explique Lookup comme ceci:

A Lookup<TKey, TElement> ressemble à un Dictionary<TKey, TValue>. La différence est qu'un Dictionary <TKey, TValue> mappe des clés à des valeurs uniques, tandis qu'un Lookup <TKey, TElement> mappe des clés à des collections de valeurs.

Je ne trouve pas cette explication particulièrement utile. À quoi sert la recherche?

dan-gph
la source

Réponses:

215

C'est un croisement entre un IGroupinget un dictionnaire. Il vous permet de regrouper les éléments par une clé, mais d'y accéder ensuite via cette clé de manière efficace (plutôt que de simplement les parcourir tous, ce qui GroupByvous permet de faire).

Par exemple, vous pouvez prendre une charge de types .NET et créer une recherche par espace de noms ... puis accéder à tous les types d'un espace de noms particulier très facilement:

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

(J'utiliserais normalement varpour la plupart de ces déclarations, en code normal.)

Jon Skeet
la source
59
Je pense que pour améliorer cette réponse, vous pourriez remplacer certains des vars. À des fins d'apprentissage, je pense qu'il est plus facile de suivre, lorsque les types sont clairement exprimés. Juste mes 2 cents :)
Alex Baranosky
3
S'il a le meilleur des deux mondes, alors pourquoi s'embêter avec un dictionnaire?
Kyle Baran
15
@KyleBaran: Parce que cela ne servirait à rien pour les véritables collections de paires clé / valeur, où il n'y a qu'une seule valeur par clé.
Jon Skeet
12
@KyleBaran Lookup<,>est simplement une collection immuable (sans Addméthode par exemple) qui a une utilisation limitée. De plus, ce n'est pas une collection à usage général dans le sens où si vous recherchez une clé inexistante, vous obtenez une séquence vide plutôt qu'une exception, ce qui n'a de sens que dans des contextes spéciaux, par exemple avec linq. Cela va bien avec le fait que MS n'a pas fourni de constructeur public pour la classe.
nawfal
L'ordre de lecture des réponses est jwg -> bobbymcr -> jonskeet
snr
58

Une façon d'y penser est la suivante: Lookup<TKey, TElement>est similaire à Dictionary<TKey, Collection<TElement>>. Fondamentalement, une liste de zéro ou plusieurs éléments peut être renvoyée via la même clé.

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
la source
2
Peut-il y avoir zéro élément dans un résultat de recherche? Comment obtiendriez-vous cela? (La recherche est publiquement immuable pour autant que je sache, et je ne pense pas que ToLookup inventerait efficacement des clés.)
Jon Skeet
8
Techniquement, oui, puisqu'un Lookup renvoie une collection vide pour une clé inexistante (j'ai édité mon message pour ajouter un exemple de code qui le montre).
bobbymcr
L'ordre de lecture des réponses est jwg -> bobbymcr -> jonskeet
snr
Une réponse très propre et utile, je souhaite qu'elle soit sélectionnée.
mn
25

Une utilisation de Lookuppourrait être d'inverser un Dictionary.

Supposons que vous ayez un répertoire implémenté en tant que Dictionaryavec un ensemble de noms (uniques) comme touches, chaque nom étant associé à un numéro de téléphone. Mais deux personnes avec des noms différents peuvent partager le même numéro de téléphone. Ce n'est pas un problème pour a Dictionary, qui ne se soucie pas que deux clés correspondent à la même valeur.

Vous voulez maintenant un moyen de rechercher à qui appartient un numéro de téléphone donné. Vous construisez un Lookup, en ajoutant tous les à KeyValuePairspartir de votre Dictionary, mais vers l'arrière, avec la valeur comme clé et la clé comme valeur. Vous pouvez maintenant interroger un numéro de téléphone et obtenir une liste des noms de toutes les personnes dont le numéro de téléphone est. Construire un Dictionaryavec les mêmes données supprimerait des données (ou échouerait, selon la façon dont vous l'avez fait), depuis

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

signifie que la deuxième entrée écrase la première - le document n'est plus répertorié.

Essayer d'écrire les mêmes données d'une manière légèrement différente:

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

lancerait une exception sur la deuxième ligne car vous ne pouvez pas Addune clé qui est déjà dans le fichier Dictionary.

[Bien sûr, vous voudrez peut-être utiliser une autre structure de données unique pour effectuer des recherches dans les deux sens, etc. Cet exemple signifie que vous devez régénérer le à Lookuppartir de Dictionarychaque fois que ce dernier change. Mais pour certaines données, cela pourrait être la bonne solution.]

jwg
la source
La réponse est essentielle pour comprendre le concept. +1. L'ordre de lecture des réponses est jwg -> bobbymcr -> jonskeet
snr
15

Je ne l'ai jamais utilisé avec succès auparavant, mais voici mon essai:

A Lookup<TKey, TElement>se comporterait à peu près comme un index de base de données (relationnel) sur une table sans contrainte unique. Utilisez-le dans les mêmes endroits que vous utiliseriez l'autre.

Daren Thomas
la source
5

Je suppose que vous pourriez l'argumenter de cette façon: imaginez que vous créez une structure de données pour contenir le contenu d'un annuaire téléphonique. Vous voulez saisir par lastName, puis par firstName. Utiliser un dictionnaire ici serait dangereux car de nombreuses personnes peuvent porter le même nom. Ainsi, un dictionnaire sera toujours, au plus, mappé à une valeur unique.

Une recherche correspondra potentiellement à plusieurs valeurs.

Lookup ["Smith"] ["John"] sera une collection d'une taille d'un milliard.

David Andres
la source
Votre réponse a inspiré ma question de suivi "Comment rechercher () avec plusieurs index?" . Comment puis-je reproduire une telle recherche, avec plusieurs index? Pourriez-vous y répondre éventuellement en utilisant tout autre échantillon ou référence où il est possible d'utiliser Lookup["Smith"]["John"] ?
Fulproof