3
votes

C # / .NET comparant deux grandes listes et recherche des éléments manquants dans les deux listes

Donc, fondamentalement, j'ai deux grandes listes comme suit:

- A list of items that are present in newList, but not in oldList

- A list of items that are present in oldList, but not in newList

Les deux listes sont très grandes, et un simple double foreach ne serait pas suffisant en raison d'un temps d'exécution médiocre si elles sont toutes les deux grandes (plus de 30 secondes).

Dans la question précédente que j'ai posée sur stackoverflow, j'ai eu une réponse sur la façon de comparer ces deux mêmes listes et de découvrir quels éléments ont un paramètre QuantitySold différent, puis de le stocker dans une troisième liste appelée "DifferentQuantityItems" comme suit:

var differentQuantityItems =
    (from newItem in newList
     join oldItem in oldList on newItem.ItemID equals oldItem.ItemID
     where newItem.QuantitySold != oldItem.QuantitySold
     select newItem).ToList();

Maintenant, ce que je voudrais obtenir de ces deux listes est la suivante:

public class Items
{
 public string ItemID { get; set; }
}


var oldList = new List<Items>(); // oldList

var newList = new List<Items>(); // new list


7 commentaires

Quelqu'un les gars? =)


vous pouvez essayer intersection et union de LINQ docs.microsoft.com/en-us/dotnet/api/...


vous pouvez utiliser la méthode Equals avec une classe de comparaison personnalisée


l'utilisation de LINQ ne promettra aucune augmentation des performances, jetez un œil ici stackoverflow.com/questions/11124797/...


@Aarif ouh quand j'ai vu des boucles parallèles mentionnées dans l'une des réponses je me suis immédiatement enfui ... j'ai de mauvaises expériences avec des boucles parallèles hahah = D


pour obtenir un code propre, je suggérerais d'utiliser LINQ (comme mentionné précédemment), vous rencontrez un problème avec ces listes qui prennent trop de temps (pas très clair d'après votre question), vous pouvez en lancer quelques-unes tâches parallèles pour le faire plus rapidement ou mieux écrire un travail cron pour le faire.


Vous n'avez pas dit si les listes étaient triées. Il est important de le savoir avant de choisir une approche.


5 Réponses :


2
votes

Avez-vous envisagé de convertir vos listes en hashsets et d'utiliser la méthode Except?

Voir Différence entre deux listes

Et: Existe-t-il un moyen de faire la différence entre deux ensembles d'objets dans c #


2 commentaires

Ça a l'air bien, pourriez-vous me montrer un exemple si possible s'il vous plaît? :)


D'accord avec essayer Except (), car il devrait s'agir d'une complexité O (1) ou O (log N) en raison de l'utilisation interne de HashSet (bien que je ne sois pas à 100%, mais en testant cela semble être le cas)



1
votes
var items = new List<int>(oldList.Select(x => x.ItemID ));
var missingValues = newList.Where(x => !diffids.Contains(x.ItemID)).ToList();
You can also use except.

1 commentaires

Hm celui-ci est un peu déroutant pour moi ... Puis-je extraire les éléments sous forme de classe? Pas seulement la valeur entière ..: D



1
votes

Sauf fonctionnera beaucoup plus vite. Ici , vous pouvez lire ci-dessus ses performances

oldList.Concat(newList).GroupBy(x => x.ItemID).Where(x => x.Count() < 2).Select(x => x.Value).ToList()

Ancienne réponse

Deux listes différentes avec des éléments manquants

var missedOld = oldList.Where(x => !newList.Select(i => i.ItemID).Contains(x.ItemID)) 
var missedNew = newList.Where(x => !oldList.Select(i => i.ItemID).Contains(x.ItemID))

Tous les éléments manquants en une liste:

var missedOld = oldList.Except(newList, new ItemsEqualityComparer());
var oldList= oldList.Except(missedOld, new ItemsEqualityComparer());


10 commentaires

Ne devriez-vous pas créer une nouvelle variable et y stocker les nouvelles valeurs?


P.S. J'aimerais que les éléments manquants des deux listes soient séparés dans deux listes différentes ... = d


@ User987 Oui, bien sûr, vous devriez mettre la valeur de cette expression dans une nouvelle variable et l'utiliser que


cela fait-il perdre des éléments à l'ancienne ou à la nouvelle liste? :RÉ


@ User987 ok, alors utilisez simplement! Contient. Je modifierai ma réponse


Akmal, ça a l'air bien, mais comment fonctionne exactement le "Contient"? Considérez que j'ai plus d'une propriété à l'intérieur de cette classe ... Comment saura-t-elle en fonction de ce qu'elle comparera l'article? = / (Il devrait les comparer en fonction de l'ItemID


@ User987 Vous pouvez également comparer des propriétés comme celle-ci: var missingOld = oldList.Where (x =>! NewList.Select (l => l.ItemID) .Contains (x.ItemID))


Oui c'est ça :) ... Pouvez-vous poster cette réponse pour que les autres puissent la voir également?


Je ne pense pas que List.Contains () soit meilleur que les boucles imbriquées. Son O (N) - donc les boucles imbriquées seront O (n ^ 2) - l'implémentation ICollection de List n'est pas O (1) ou O (log N) qui est ce que vous voulez dans ce cas, sinon c'est la même solution il essaie d'éviter.


@codenheim Vous avez absolument raison! Merci pour votre attention. Je modifierai ma réponse.



0
votes
var items = newList.Where(n => !oldlist.Any(o => o.ItemID == n.ItemID)).ToList();
Its more agile since you do not need to go to DB again and do not use the Contains which is like a like in SQL and it is also in a line..

0 commentaires

0
votes

Si les listes sont suffisamment grandes pour que les boucles imbriquées prennent 30 secondes, je vous recommande de placer les éléments de chaque liste dans un HashSet respectif et de l'utiliser pour trouver les exceptions. Les tables de hachage seront mises à l'échelle à O (1) ou O (log N) alors que la comparaison de 2 listes non triées est O (n ^ 2).

Cela dit, essayez d'utiliser Linq Except ()

var notinNewList = oldList.Except(newList);


0 commentaires