web-dev-qa-db-fra.com

Différence entre Lookup () et Dictionary (Of list ())

J'essaie de comprendre quelles sont les structures de données les plus efficaces et quand/où les utiliser.

Maintenant, il se peut que je ne comprenne tout simplement pas assez les structures, mais en quoi une ILookup(of key, ...) est-elle différente d'un Dictionary(of key, list(of ...))?

Aussi, où voudrais-je utiliser un ILookup et où serait-il plus efficace en termes de vitesse du programme/accès mémoire/données, etc.?

147
John Bustos

Deux différences significatives:

  • Lookup est immuable. Yay :) (Du moins, je pense que la classe concrète Lookup est immuable, et que l'interface ILookup ne fournit aucun membre en mutation. Là pourrait soit d'autres implémentations mutables, bien sûr.)
  • Lorsque vous recherchez une clé qui n'est pas présente dans une recherche, vous obtenez une séquence vide à la place d'un KeyNotFoundException. (Il n'y a donc pas de TryGetValue, AFAICR.)

Ils sont susceptibles d’être équivalents en efficacité - la recherche peut très bien utiliser un Dictionary<TKey, GroupingImplementation<TValue>> En coulisse, par exemple. Choisissez entre eux en fonction de vos besoins. Personnellement, je trouve que la recherche est généralement un meilleur ajustement qu'un Dictionary<TKey, List<TValue>>, Principalement en raison des deux premiers points ci-dessus.

Notez qu'en tant que détail d'implémentation, l'implémentation concrète de IGrouping<,> Utilisée pour les valeurs implémente IList<TValue>, Ce qui signifie qu'il est efficace de l'utiliser avec Count(), ElementAt() etc.

229
Jon Skeet

Il est intéressant de noter que personne n’a indiqué la plus grande différence réelle (directement à partir de MSDN ):

Une recherche ressemble à un dictionnaire. La différence est qu'un dictionnaire mappe des clés à des valeurs uniques, tandis qu'une recherche mappe des clés à des collections de valeurs.

35

Un Dictionary<Key, List<Value>> Et un Lookup<Key, Value> Peuvent logiquement contenir des données organisées de la même manière et sont tous deux du même ordre d'efficacité. La principale différence est que Lookup est immuable: il n’a pas de méthode Add() ni de constructeur public (et comme Jon l’a mentionné, vous pouvez interroger une clé non existante sans exception et avoir la clé as partie du groupement).

Pour ce qui vous utilisez, cela dépend vraiment de la façon dont vous voulez les utiliser. Si vous conservez une mappe de clé pour plusieurs valeurs constamment modifiée, un Dictionary<Key, List<Value>> Est probablement préférable car il est modifiable.

Si, toutefois, vous avez une séquence de données et souhaitez simplement obtenir une vue en lecture seule des données organisée par clé, une recherche est très facile à construire et vous donnera un instantané en lecture seule.

32
James Michael Hare

La principale différence entre un ILookup<K,V> et un Dictionary<K, List<V>> est qu'un dictionnaire est modifiable; vous pouvez ajouter ou supprimer des clés, mais aussi ajouter ou supprimer des éléments de la liste qui est recherchée. Un ILookup est immuable et ne peut pas être modifié une fois créé.

L'implémentation sous-jacente des deux mécanismes sera identique ou similaire, de sorte que leur vitesse de recherche et leur empreinte mémoire seront approximativement les mêmes.

11
Servy

Une autre différence qui n’a pas encore été mentionnée est que Lookup () prend en charge les clés nulles :

La classe Lookup implémente l'interface ILookup. Lookup est très similaire à un dictionnaire, sauf que plusieurs valeurs peuvent être mappées sur la même clé et que les clés nulles sont prises en charge.

9

Quand une exception n'est pas une option, optez pour Lookup

Si vous essayez d'obtenir une structure aussi efficace qu'un Dictionary mais que vous ne savez pas avec certitude qu'il n'y a pas de clé dupliquée en entrée, Lookup est plus sûr.

Comme indiqué dans une autre réponse, il prend également en charge les clés nulles et renvoie toujours un résultat valide lorsqu'il est interrogé avec des données arbitraires. Par conséquent, il semble plus résistant aux entrées inconnues (moins enclin que Dictionary à générer des exceptions).

Et c'est particulièrement vrai si vous le comparez à la System.Linq.Enumerable.ToDictionary une fonction :

// won't throw
new[] { 1, 1 }.ToLookup(x => x); 

// System.ArgumentException: An item with the same key has already been added.
new[] { 1, 1 }.ToDictionary(x => x);

L'alternative serait d'écrire votre propre code de gestion de clé dupliqué à l'intérieur d'une boucle foreach.

Considérations sur les performances, Dictionnaire: un gagnant clair

Si vous n'avez pas besoin d'une liste et que vous allez gérer un grand nombre d'éléments, Dictionary (ou même votre propre structure personnalisée) serait plus efficace:

        Stopwatch stopwatch = new Stopwatch();
        var list = new List<string>();
        for (int i = 0; i < 5000000; ++i)
        {
            list.Add(i.ToString());
        }
        stopwatch.Start();
        var lookup = list.ToLookup(x => x);
        stopwatch.Stop();
        Console.WriteLine("Creation: " + stopwatch.Elapsed);

        // ... Same but for ToDictionary
        var lookup = list.ToDictionary(x => x);
        // ...

Comme Lookup doit maintenir une liste d'éléments pour chaque clé, il est plus lent que Dictionary (environ 3 fois plus lent pour un très grand nombre d'éléments)

Recherche dans la vitesse: Création: 00: 00: 01.5760444

Vitesse du dictionnaire: Création: 00: 00: 00.4418833

4
Fab