3 votes

Trouver les différences entre deux collections de 40 000 objets

J'ai deux collections contenant toutes deux le même type d'objet et les deux collections ont environ 40 000 objets chacune.

Le code pour l'objet que chaque collection contient est fondamentalement comme un dictionnaire, sauf que j'ai surchargé les fonctions equals et hash :

public class MyClass: IEquatable<MyClass>
{
    public int ID { get; set; }
    public string Name { get; set; }

    public override bool Equals(object obj)
    {
        return obj is MyClass && this.Equals((MyClass)obj);
    }

    public bool Equals(MyClass ot)
    {
        if (ReferenceEquals(this, ot))
        {
            return true;
        }

        return 
         ot.ID.Equals(this.ID) &&
         string.Equals(ot.Name, this.Name, StringComparison.OrdinalIgnoreCase); 
    }

    public override int GetHashCode()
    {
         unchecked
         {
             int result = this.ID.GetHashCode();
             result = (result * 397) ^ this.Name.GetSafeHashCode();
             return result;
         }
    }
}

Le code que j'utilise pour comparer les collections et obtenir les différences est juste une simple requête Linq utilisant PLinq.

ParallelQuery p1Coll = sourceColl.AsParallel();
ParallelQuery p2Coll = destColl.AsParallel();

List<object> diffs = p2Coll.Where(r => !p1Coll.Any(m => m.Equals(r))).ToList();

Quelqu'un connaît-il un moyen plus rapide de comparer autant d'objets ? Actuellement, cela prend environ 40 secondes +/- 2 secondes sur un ordinateur à quatre cœurs. Serait-il plus rapide de regrouper les données, puis de comparer chaque groupe de données en parallèle ? Si je regroupe d'abord les données en fonction du nom, j'obtiendrai environ 490 objets uniques, et si je les regroupe d'abord par ID, j'obtiendrai environ 622 objets uniques.

15voto

thclpr Points 127

Vous pouvez utiliser Sauf qui vous donnera tous les éléments de p2Coll qui n'est pas dans p1Coll .

var diff = p2Coll.Except(p1Coll);

UPDATE (quelques tests de performance) :

Avis de non-responsabilité :

Le temps réel dépend de multiples facteurs (comme le contenu des collections, le matériel, ce qui tourne sur votre machine, le nombre de collisions de hashcode, etc.), c'est pourquoi nous avons la complexité et la notation Big O (voir le commentaire de Daniel Brückner).

Voici quelques statistiques de performance pour 10 exécutions sur ma machine de 4 ans :

Median time for Any(): 6973,97658ms
Median time for Except(): 9,23025ms

Code source pour mon test est disponible sur gist.


UPDATE 2 :

Si vous voulez avoir des éléments différents de la première et de la deuxième collection, vous devez en fait faire Attendez-vous à sur les deux et que Union le résultat :

var diff = p2Coll.Except(p1Coll).Union(p1Coll.Except(p2Coll));

0voto

Chris Ayers Points 49

Intersect

int[] id1 = { 44, 26, 92, 30, 71, 38 };
int[] id2 = { 39, 59, 83, 47, 26, 4, 30 };

IEnumerable<int> both = id1.Intersect(id2);

foreach (int id in both)
    Console.WriteLine(id);

/*
This code produces the following output:

26
30
*/

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X