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
5 Réponses :
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 #
Ç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)
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.
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
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());
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.
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..
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);
Quelqu'un les gars? =)
vous pouvez essayer
intersection
etunion
deLINQ
docs.microsoft.com/en-us/dotnet/api/...vous pouvez utiliser la méthode
Equals
avec une classe de comparaison personnaliséel'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.