当我有2个List<string>
个对象时,我可以直接使用Intersect
和Except
来获取输出IEnumerable<string>
。这很简单,但是如果我想要更复杂的东西的交叉/分离呢?
示例,尝试获取ClassA
对象ClassA
对象的AStr1
和ClassB
对象的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);
}
}
个对象的集合; :
{{1}}
如何修复注意到的线以实现此交叉。
答案 0 :(得分:12)
MoreLINQ有ExceptBy
。它还没有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
,一个用于{{1}一个用于公共密钥类型)。
答案 1 :(得分:3)
x∈A∩B当且仅当x∈A且x∈B时才有。
因此,对于a
中的每个aObj
,您可以检查a.AStr1
值是否属于BStr
。
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));
}
答案 2 :(得分: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"));
}