使用LINQ来对象在特定属性上相交和除外

Dia*_*ana 6 c# linq-to-objects intersect

当我有2个List<string>对象,那么我可以使用Intersect,并Except在他们身上直接得到一个输出IEnumerable<string>.这很简单,但是如果我想要更复杂的东西的交集/分离怎么办?

例如,尝试获取ClassA对象的集合,这是ClassA对象AStr1ClassB对象的交叉结果BStr; :

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

如何修复注意到的线以实现此交集.

Jon*_*eet 12

更多LINQExceptBy.它还IntersectBy没有,但你可以轻松编写自己的实现,甚至可能在之后将它贡献给MoreLINQ :)

它可能会看东西像这样(忽略错误检查):

public static IEnumerable<TSource> IntersectBy<TSource, TKey>(
    this IEnumerable<TSource> first,
    IEnumerable<TSource> second,
    Func<TSource, TKey> keySelector,
    IEqualityComparer<TKey> keyComparer)
{
    HashSet<TKey> keys = new HashSet<TKey>(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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你想在两个完全不同的类型上执行一个碰巧有一个共同属性类型的交集,你可以使用三个类型参数(一个用于first,一个用于second公共密钥类型,一个用于公用密钥类型)制作更通用的方法.