Utilisation de LINQ avec les objects Intersect et Except sur une propriété spécifique

Lorsque j’ai 2 objects List , je peux utiliser directement Intersect et Except pour obtenir une sortie IEnumerable . C’est assez simple, mais si je veux l’intersection / la disjonction sur quelque chose de plus complexe?

Exemple, essayer d’obtenir une collection d’objects ClassA qui est le résultat de l’intersection sur l’object ClassA object AStr1 et ClassB object ClassB object BStr ; :

 public class ClassA { public ssortingng AStr1 { get; set; } public ssortingng AStr2 { get; set; } public int AInt { get; set; } } public class ClassB { public ssortingng BStr { get; set; } public int BInt { get; set; } } public class Whatever { public void xyz(List aObj, List bObj) { // *** this line is horribly incorrect *** IEnumberable result = aObj.Intersect(bObj).Where(a, b => a.AStr1 == b.BStr); } } 

Comment puis-je réparer la ligne indiquée pour réaliser cette intersection?

MoreLINQ a ExceptBy . Il n’a pas encore IntersectBy , mais vous pouvez facilement écrire votre propre implémentation et éventuellement même la consortingbuer à MoreLINQ par la suite 🙂

Cela ressemblerait probablement à quelque chose comme ceci (en omettant la vérification d’erreur):

 public static IEnumerable IntersectBy( this IEnumerable first, IEnumerable second, Func keySelector, IEqualityComparer keyComparer) { HashSet keys = new HashSet(first.Select(keySelector), keyComparer); foreach (var element in second) { TKey key = keySelector(element); // Remove the key so we only yield once if (keys.Remove(key)) { yield return element; } } } 

Si vous souhaitez effectuer une intersection sur deux types complètement différents possédant un type de propriété commun, vous pouvez créer une méthode plus générale avec trois parameters de type (un pour le first , un pour le second et un pour le type de clé commune).

x ∈ A ∩ B si et seulement si x A et x B.

Donc, pour chaque a dans aObj , vous pouvez vérifier si a.AStr1 est dans l’ensemble des valeurs BStr .

 public void xyz(List aObj, List bObj) { HashSet bstr = new HashSet(bObj.Select(b => b.BStr)); IEnumerable result = aObj.Where(a => bstr.Contains(a.AStr1)); } 

ce code:

  public IEnumerable xyz(List aObj, List bObj) { IEnumerable bStrs = bObj.Select(b => b.BStr).Distinct(); return aObj.Join(bStrs, a => a.AStr1, b => b, (a, b) => a); } 

a réussi le test suivant:

  [TestMethod] public void PropertyIntersectionBasedJoin() { List aObj = new List() { new ClassA() { AStr1 = "a" }, new ClassA() { AStr1 = "b" }, new ClassA() { AStr1 = "c" } }; List bObj = new List() { new ClassB() { BStr = "b" }, new ClassB() { BStr = "b" }, new ClassB() { BStr = "c" }, new ClassB() { BStr = "d" } }; var result = xyz(aObj, bObj); Assert.AreEqual(2, result.Count()); Assert.IsFalse(result.Any(a => a.AStr1 == "a")); Assert.IsTrue(result.Any(a => a.AStr1 == "b")); Assert.IsTrue(result.Any(a => a.AStr1 == "c")); }