6

当我有 2 个List<string>对象时,我可以直接在它们上使用IntersectandExcept来获得输出IEnumerable<string>。这很简单,但是如果我想要更复杂的东西上的交集/析取呢?

例如,试图获取对象集合,这是对象和对象ClassA相交的结果;:ClassAAStr1ClassBBStr

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);
    }
}

我怎样才能修复注意到的线来实现这个交叉点。

4

3 回答 3

14

更多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;
        }
    }
}

如果您想对碰巧具有共同属性类型的两种完全不同的类型执行交集,您可以使用三个类型参数(一个用于first,一个用于second,一个用于公共键类型)创建一个更通用的方法。

于 2010-10-22T15:17:38.427 回答
3

x ∈ A ∩ B 当且仅当 x ∈ A 且 x ∈ B。

因此,对于每个ain aObj,您可以检查是否a.AStr1BStr值集中。

public void xyz(List<ClassA> aObj, List<ClassB> bObj)
{
    HashSet<string> bstr = new HashSet<string>(bObj.Select(b => b.BStr));
    IEnumerable<ClassA> result = aObj.Where(a => bstr.Contains(a.AStr1));
}
于 2010-10-22T15:21:51.380 回答
1

这段代码:

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

已通过以下测试:

    [TestMethod]
    public void PropertyIntersectionBasedJoin()
    {
        List<ClassA> aObj = new List<ClassA>()
                                {
                                    new ClassA() { AStr1 = "a" }, 
                                    new ClassA() { AStr1 = "b" }, 
                                    new ClassA() { AStr1 = "c" }
                                };
        List<ClassB> bObj = new List<ClassB>()
                                {
                                    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"));
    }
于 2010-10-26T02:06:33.163 回答