web-dev-qa-db-fra.com

C #: Pourquoi le dictionnaire est-il tellement plus rapide que la liste?

Je teste la vitesse d'obtention des données de la liste Dictionary VS.
J'ai utilisé ce code pour tester:

    internal class Program
{
    private static void Main(string[] args)
    {
        var stopwatch = new Stopwatch();
        List<Grade> grades = Grade.GetData().ToList();
        List<Student> students = Student.GetStudents().ToList();

        stopwatch.Start();
        foreach (Student student in students)
        {
            student.Grade = grades.Single(x => x.StudentId == student.Id).Value;
        }
        stopwatch.Stop();
        Console.WriteLine("Using list {0}", stopwatch.Elapsed);
        stopwatch.Reset();
        students = Student.GetStudents().ToList();
        stopwatch.Start();
        Dictionary<Guid, string> dic = Grade.GetData().ToDictionary(x => x.StudentId, x => x.Value);
        foreach (Student student in students)
        {
            student.Grade = dic[student.Id];
        }
        stopwatch.Stop();
        Console.WriteLine("Using dictionary {0}", stopwatch.Elapsed);
        Console.ReadKey();
    }
}

public class GuidHelper
{
    public static List<Guid> ListOfIds=new List<Guid>();

    static GuidHelper()
    {
        for (int i = 0; i < 10000; i++)
        {
            ListOfIds.Add(Guid.NewGuid());
        }
    }
}


public class Grade
{
    public Guid StudentId { get; set; }
    public string Value { get; set; }

    public static IEnumerable<Grade> GetData()
    {
        for (int i = 0; i < 10000; i++)
        {
            yield return new Grade
                             {
                                 StudentId = GuidHelper.ListOfIds[i], Value = "Value " + i
                             };
        }
    }
}

public class Student
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string Grade { get; set; }

    public static IEnumerable<Student> GetStudents()
    {
        for (int i = 0; i < 10000; i++)
        {
            yield return new Student
                             {
                                 Id = GuidHelper.ListOfIds[i],
                                 Name = "Name " + i
                             };
        }
    }
}

Il y a une liste d'étudiants et de notes en mémoire, ils ont StudentId en commun.
D’abord, j’ai essayé de trouver le grade d’un élève à l’aide de LINQ sur une liste prenant près de 7 secondes sur ma machine. moins d'une seconde. enter image description here

61
Unforgiven

Quand tu fais ça:

student.Grade = grades.Single(x => x.StudentId == student.Id).Value;

Comme écrit, il doit énumérer la totalité de List jusqu'à ce qu'il trouve l'entrée dans la liste qui a le bon studentId (l'entrée 0 correspond-elle au lambda? Non ... L'entrée 1 correspond-elle au lambda? Non ... etc). C'est O (n). Puisque vous le faites une fois pour chaque élève, c'est O (n ^ 2).

Cependant, lorsque vous faites cela:

student.Grade = dic[student.Id];

Si vous voulez trouver un certain élément à l'aide d'une clé dans un dictionnaire, il peut instantanément aller là où il se trouve dans le dictionnaire - c'est O (1). O(n) pour chaque élève. Si vous voulez savoir comment cela se passe, le dictionnaire exécute une opération mathématique sur la clé, qui la transforme en une valeur qui est un lieu. à l'intérieur du dictionnaire, qui est le même endroit il le met quand il a été inséré)

Donc, dictionnaire est plus rapide parce que vous avez utilisé un meilleur algorithme.

116
Patashu

Lorsque vous utilisez Dictionary, vous utilisez une clé pour récupérer vos informations, ce qui lui permet de les trouver plus efficacement, avec List vous utilisez Single expression Linq, qui est une liste, n'a pas d'autre option que de regarder dans la liste entière pour l'élément recherché.

11
Ron.B.I

La raison en est qu'un dictionnaire est une recherche, alors qu'une liste est une itération.

Le dictionnaire utilise une recherche par hachage, tandis que votre liste nécessite de parcourir la liste jusqu'à trouver le résultat depuis le début jusqu'au résultat à chaque fois.

pour le dire autrement. La liste sera plus rapide que le dictionnaire sur le premier élément, car il n'y a rien à rechercher. c'est le premier article, boum .. c'est fait. mais la deuxième fois, la liste doit parcourir le premier élément, puis le deuxième. La troisième fois, il doit parcourir le premier élément, puis le deuxième élément, puis le troisième élément, etc.

Ainsi, à chaque itération, la recherche prend de plus en plus de temps. Plus la liste est longue, plus cela prend du temps. Bien que le dictionnaire ait toujours une durée de recherche plus ou moins fixe (il augmente également à mesure que le dictionnaire grossit, mais à un rythme beaucoup plus lent, donc, en comparaison, il est presque fixe).

10
Erik Funkenbusch

Le dictionnaire utilise le hachage pour rechercher les données. Chaque élément du dictionnaire est stocké dans des compartiments contenant le même hachage. C'est beaucoup plus rapide.

Essayez de trier votre liste, ce sera un peu plus rapide alors.

8

Un dictionnaire utilise une table de hachage , c'est une excellente structure de données car il mappe une entrée sur une sortie correspondante presque instantanément, il présente une complexité de O(1) comme déjà indiqué, ce qui signifie une récupération plus ou moins immédiate.

Le seul inconvénient, c’est que, pour des raisons de performance, vous avez besoin de beaucoup d’espace à l’avance (selon l’implémentation, que ce soit une analyse en chaîne séparée ou une analyse linéaire/quadratique, vous devrez peut-être au moins autant que ce que vous envisagez de stocker. dernier cas) et vous avez besoin d’un bon algorithme de hachage qui mappe de manière unique votre entrée ("John Smith") vers une sortie correspondante telle qu'une position dans un tableau (hash_array[34521]).

La liste des entrées dans un ordre trié pose également un problème. Si je peux citer Wikipedia:

La liste de n entrées dans un ordre spécifique nécessite généralement une étape de tri distincte, dont le coût est proportionnel à log (n) par entrée.

Ayez une lecture sur sondage linéaire et chaînage séparé pour certains détails plus gorier :)

6
Nobilis

Dictionnaire est basé sur une table de hachage qui est un algorithme plutôt efficace pour rechercher des choses. Dans une liste, vous devez aller élément par élément pour trouver quelque chose.

Tout est une question d'organisation des données ...

3
JeffRSon

Lorsqu'il s'agit de rechercher des données, une collection avec clé est toujours plus rapide qu'une collection sans clé. En effet, une collection sans clé devra énumérer ses éléments pour trouver ce que vous recherchez. Dans une collection avec clé, vous pouvez simplement accéder à l'élément directement via la clé.

Voici quelques articles de Nice pour comparer la liste au dictionnaire.

ici . Et ceci n .

2
aiapatag