2012-09-26 4 views
4

Je suis assez nouveau à LINQ et je me suis peut-être peint dans un coin ici. J'ai deux listes (gauche et droite) et je dois:Obtenir la différence entre deux listes basées sur certains champs

un) Obtenez des produits correspondant à la base de certains champs

b) Obtenir des éléments à gauche sans match sur le droit

c) Obtenez des articles sur le droit sans match sur la gauche

Un match se trouve si certains champs sont égaux. Les autres champs peuvent ou non contenir des valeurs mais ne doivent pas influencer la comparaison de correspondance.

Pour obtenir l'article un j'ai effectué une JOIN sur les deux listes:

var q = from a in r1 
     from b in r2 
     where a.Prop1 == b.Prop1 && a.Prop3 == b.Prop3 
     select new { a.Prop1, a.Prop2, b.Prop3 }; 

Je ne sais pas où aller d'ici. I pense Je ne peux pas utiliser .Except() parce que les autres propriétés pour les deux listes seront différentes et peuvent entraîner la rupture de la comparaison.

J'ai aussi essayé d'utiliser Left Join et obtenir les articles sans matches:

var q = 
    from c in r1 
    join p in r2 on c.Prop1 equals p.Prop1 
    into cp 
    from p in cp.DefaultIfEmpty() 
    select new { Prop1 = c.Prop1, Prop2 = p == null ? "N/A" : p.Prop2 }; 

mais je trouve que vous ne pouvez pas comparer plus d'un champ à comparer.

Pouvez-vous avoir plus d'un champs sur un Left Join avec LINQ? Existe-t-il d'autres moyens (outre LINQ) pour faire la différence entre deux listes?

Répondre

4

Cette utilise Intersect et Except (similaire à la solution de Cuong Le):

public class MyComparer : IEqualityComparer<YourClass> 
{ 
    #region IEqualityComparer<YourClass> Members 

    public bool Equals(YourClass x, YourClass y) 
    { 
     return 
      x.Prop1.Equals(y.Prop1) && x.Prop3.Equals(y.Prop3); 
    } 

    public int GetHashCode(YourClass obj) 
    { 
     int hCode = obj.Prop1.GetHashCode()^obj.Prop3.GetHashCode(); 
     return hCode.GetHashCode(); 
    } 

    #endregion 
} 

// matched elements from both lists 
var r1 = l1.Intersect<YourClass>(l2, new MyComparer()); 
// elements from l1 not in l2 
var r2 = l1.Except<YourClass>(l2, new MyComparer()); 
// elements from l2 not in l1 
var r3 = l2.Except<YourClass>(l1, new MyComparer()); 
+0

Merci.J'ai utilisé un hybride vôtre et la solution de Cuong Le. Je ne savais pas qu'il y avait un 'Intersect' donc ça va me sauver le 'InnerJoin' – Devmonster

+0

De rien, je suis heureux de vous aider. –

0

Que diriez-vous

a)

r1.Where(x=>r2.Any(y=>x.Prop1==y.Prop1&&x.Prop3==y.Prop3)) 
    .Select(x=>new { x.Prop1,x.Prop2,x.Prop3}); 

b)

r1.Where(x=>!r2.Any(y=>x.Prop1==y.Prop1&&x.Prop3==y.Prop3)) 
    .Select(x=>new { x.Prop1,x.Prop2,x.Prop3}); 

c)

r2.Where(x=>!r1.Any(y=>x.Prop1==y.Prop1&&x.Prop3==y.Prop3)) 
    .Select(x=>new { x.Prop1,x.Prop2,x.Prop3}); 
2

Par défaut, Except utilisation de la méthode EqualityComparer.Default, qui est la raison pour laquelle vous ne pouvez pas utiliser si vous avez des objets avec la propriété différentes valeurs

Mais vous pouvez utiliser une autre méthode de surcharge Except pour personnaliser EqualityComparer<T>, supposons qu'il ne tient pas compte Pro3

public class CustomComparer : EqualityComparer<A> 
{ 
    public override int GetHashCode(A a) 
    { 
     int hCode = a.Pro1.GetHashCode()^a.Pro2.GetHashCode(); 
     return hCode.GetHashCode(); 
    } 

    public override bool Equals(A a1, A a2) 
    { 
     return a1.Pro1.Equals(a2.Pro1) && a1.Pro2.Equals(a2.Pro2) 
    } 
} 

vous pouvez utiliser Except:

listA.Except(listB, new CustomComparer()); 
+0

Merci, bien que sur votre code 'listA.Except (listA ...' Je pense que vous vouliez dire 'listB' sur le 2ème' listA'. – Devmonster

Questions connexes