2011-04-13 6 views
1

J'ai deux listes génériques où je veux courir quelques requêtes LINQ pour savoir:requête LINQ pour choisir entre la différence des listes génériques

  1. Est-ce que des listes A objets trouvés dans la liste B

  2. -ce que toutes les listes A objets trouvés dans la liste B

Voici la liste:

var ListA = new List<long>() 
var ListB = new List<MyObject>() 

MyObject est défini comme:

public class MyObject 
    { 
    public long ItemId { get; set; }  
    // ... Other stuff... 
    } 

Je suis en train de déterminer deux choses (deux requêtes): 1. Effectuez l'une des positions longues à ListA correspond à l'un MyObject.ItemId dans Liste_B? Et 2. Peut-on trouver tous les longs dans ListA dans ListB?

ListA et ListB peuvent avoir des longueurs différentes. Pour le numéro 2, j'aurais besoin de tous les éléments de ListA trouvés dans ListB, mais pas l'inverse. J'espère que cela a du sens.

Merci,

-SCOTT

+0

Je suis un peu confus au sujet de la partie 2. Est-ce que vous voulez savoir si tous les éléments ListA sont contenus dans les Itemid de B de ou voulez-vous une liste de valeurs ListA contenues dans les ItemId de B. Questions légèrement différentes. Ta dernière phrase c'est ce qui m'a confondu. –

+0

Je veux que chaque long dans ListA soit égal à au moins un MyObject.ItemId dans ListB. – Scott

Répondre

6

D'abord, vous ne se soucient que les itemID à Liste_B, donc:

var bIDs = ListB.Select(x => x.ItemId); 

Pour répondre à la première partie de votre question, je approchez-vous en trouvant l'intersection des deux listes (l'ensemble de tous les éléments qu'ils partagent). S'il y a au moins un élément, il y a chevauchement entre les deux.

var sharedIds = ListA.Intersect(bIDs); 
if (sharedIds.Any()) 
    // list A contains at least one ItemID which ListB contains 

Quant à la deuxième partie, vous voulez voir si la liste A est un sous-ensemble de la liste B. Recherche de cela, le débordement de pile présente un clean solution:

if (!ListA.Except(bIDs).Any()) 
    // yes, list A is a subset of list B 

Cet extrait fonctionne parce que ListA.Except(bIDs) trouve les éléments qui ont ListA ne le font pas bIDs. Si cela est vide, alors ListA ne contient rien que bIDs ne contient pas. Ainsi, tout ce qui est en ListA est également en bIDs. Voici un exemple: A = {1, 2}; B = {1, 2, 3}. A est un sous-ensemble de B. A.Except(B) vous donne un ensemble vide - B a à la fois 1 et 2, donc ne peut pas être dans la liste résultante, et il n'y a plus rien dans B. Alors quand A est un sous-ensemble de B, A.Except(B).Any() donne false, car il n'y a aucun élément dans le résultat; donc nous le nions évidemment si nous voulons gérer ce cas. Pour être complet, si nous remplaçons A et B par un tour, de sorte que A ne soit pas un sous-ensemble de B: A = {1, 2, 3}; B = {1, 2}, puis A.Except(B) donne {3}. Il ne peut pas contenir 1 ou 2, parce que B contient 1 et 2. Mais B ne contient pas 3, donc A.Except(B)peut contenir. Comme {3} contient un élément, il n'est pas vide, donc A.Except(B).Any() est vrai. Négatif, il est faux si A n'est pas un sous-ensemble de B.

Mon explication est un peu laconique; Si vous voulez regarder les choses plus loin (et je vous recommande de le faire - une petite théorie des ensembles peut aller un long chemin), A.Except(B) est le nom de LINQ pour la différence de jeu, ou complément de jeu relatif. Wikibooks a un introduction décent pour établir la théorie si vous êtes si incliné.

+0

+1 Beaucoup plus propre que ce à quoi j'allais répondre. – Davy8

+1

Sûrement c'est plus compliqué que nécessaire .. – flesh

+0

@flesh: Avec le 'si's, etc. c'est un peu bavard; Y a-t-il quelque chose en particulier qui pourrait être simplifié? –

1
var value1 = 
(
    from itemA in ListA 
    where ListB.Any(itemB => itemB.ItemID == itemA) 
    select item 
).Count(); 

var value2 = value1 == ListA.Count(); 
0

Pour tester simplement les conditions, en supposant extraire une liste de ItemIds en listB:

bool inListA = listA.Any(x => listB.Contains(x)); 

bool allInListB = listA.All(x => listB.Contains(x)); 

Pour tester en place sans extraire une liste séparée si ItemIds

bool inListA = listA.Any(x => listB.Select(b => b.ItemId).Contains(x)); 

bool allInListB = listA.All(x => listB.Select(b => b.ItemId).Contains(x)); 
0

Si vous avez besoin de répondre Les trois questions en même temps, il est probable qu'une solution LINQ pure ne sera pas optimale, puisque les requêtes individuelles devront chacune effectuer la même opération d'intersection. Faites l'intersection une fois, puis utiliser ce résultat pour répondre à vos trois questions:

var tempSet = new HashSet<long>(ListA); 
int uniqueAItemCount = tempSet.Count; 

// 2b. "I would need all of ListA's items found in ListB, but not vice-versa." 
tempSet.IntersectWith(ListB.Select(x => x.ItemId)); 
// tempSet now contains all items from ListA also found in ListB 
// we can use this result to answer the other two questions... 

// 1. "Do any of the longs in ListA match any of the MyObject.ItemId in ListB?" 
bool anyAFoundInB = tempSet.Count > 0; 

// 2a. "Can all of the longs in ListA be found in ListB?" 
bool allAFoundInB = tempSet.Count == uniqueAItemCount; 
Questions connexes