我试图找到与LINQ的交叉。
我有这样的对象:
public class objA
{
public int foo1{ get; set; }
public string foo2 { get; set; }
public bool foo3 { get; set; }
}
样品:
List<objA> name1= new List<int>() {{1,"bb",true} , {2,"cc",false}};
List<objA> name2= new List<int>();
List<objA> name3= new List<int>() { {1,"bb",true} };
List<objA> name4= new List<int>() { {1,"bb",true} , {2,"cc",false} };
List<objA> name5= new List<int>() { {1,"bb",true} };
想要返回:{1,&#34; bb&#34;,true},因为它存在于所有列表中..如果我运行:
List<objA>= name1
.Intersect(name2)
.Intersect(name3)
.Intersect(name4)
.Intersect(name5).ToList();
当列表2为空时,它不返回任何内容。
我知道这条消息: LINQ intersect, multiple lists, some empty
但我不知道如何处理对象。
答案 0 :(得分:2)
首先,让我们定义一个执行交集的扩展方法,但忽略任何空的列表。
public static class Ex
{
public static IEnumerable<T> IntersectIgnoreEmpty<T>(this IEnumerable<T> @this, IEnumerable<T> other, IEqualityComparer<T> comparer)
{
return other.Any() ? @this.Intersect(other, comparer) : @this;
}
}
现在我们为objA
定义一个相等比较器:
public class objAEqualityComparer : IEqualityComparer<objA>
{
public bool Equals(objA left, objA right)
{
return
left.foo1 == right.foo1
&& left.foo2 == right.foo2
&& left.foo3 == right.foo3;
}
public int GetHashCode(objA @this)
{
return
@this.foo1.GetHashCode()
^ @this.foo2.GetHashCode()
^ @this.foo3.GetHashCode();
}
}
然后我们可以运行这段代码:
List<objA> name1 = new List<objA>()
{
new objA { foo1 = 1, foo2 = "bb", foo3 = true },
new objA { foo1 = 2, foo2 = "cc", foo3 = false },
};
List<objA> name2 = new List<objA>();
List<objA> name3 = new List<objA>() { new objA { foo1 = 1, foo2 = "bb", foo3 = true } };
List<objA> name4 = new List<objA>()
{
new objA { foo1 = 1, foo2 = "bb", foo3 = true },
new objA { foo1 = 2, foo2 = "cc", foo3 = false },
};
List<objA> name5 = new List<objA>() { new objA { foo1 = 1, foo2 = "bb", foo3 = true } };
objAEqualityComparer comparer = new objAEqualityComparer();
List<objA> result =
name1
.IntersectIgnoreEmpty(name2, comparer)
.IntersectIgnoreEmpty(name3, comparer)
.IntersectIgnoreEmpty(name4, comparer)
.IntersectIgnoreEmpty(name5, comparer)
.ToList();
我们得到的结果是:
您可以始终覆盖Equals
中的GetHashCode
和objA
,但这需要将objA
设为只读,以便不破坏平等合同 - 制作{在这种情况下,{1}}是更好的选择,因为它允许{/ 1}}进行读/写。
答案 1 :(得分:0)
首先,name2为空。 &#34;相交&#34;总是什么也没有。所以删除name2。
List<objA> output = name1
.Intersect(name3)
.Intersect(name4)
.Intersect(name5).ToList();
其次,删除&#34; .Intersect(name2)&#34;仍然什么都没有。
因为你必须同时实施&#34; Equal&#34;和&#34; GetHashCode&#34;自定义类中的方法。
public class objA
{
public int foo1{ get; set; }
public string foo2 { get; set; }
public bool foo3 { get; set; }
public override bool Equals(object obj)
{
if (obj is objA == false) return false;
var a = (objA)obj;
return a.foo1 == foo1
&& a.foo2 == foo2
&& a.foo3 == foo3;
}
public override int GetHashCode()
{
return foo1.GetHashCode()
^ foo2.GetHashCode()
^ foo3.GetHashCode();
}
}
这是因为&#34;相交&#34;使用&#34;等于&#34;比较对象。 它使用&#34; GetHashCode&#34;加快速度。
答案 2 :(得分:0)
如果您想要准确理解为什么您的代码不起作用,那么Tommy的答案是完美的 - 删除&#34; .Intersect(name2)&#34; line(因为&#34; name2&#34;没有任何项目,因此与它相交将始终返回零结果)然后在你的&#34; objA&#34;上实现GetHashCode和Equals方法。类。
但是,如果您只是想以最简单的方式使代码工作,您可以将objA从类更改为结构,因为结构会自动接收GetHashCode和Equals实现,它们可以执行您想要的操作。
我修复了原始代码,以便编译和更改&#34; objA&#34;进入一个结构,现在是最后的&#34; x&#34; value将是一个具有单个值的列表(foo1 = 1,foo2 =&#34; bb&#34;,foo3 = true)。
using System.Collections.Generic;
using System.Linq;
namespace StackOverflowAnswer
{
public struct objA
{
public int foo1 { get; set; }
public string foo2 { get; set; }
public bool foo3 { get; set; }
}
class Program
{
static void Main()
{
List<objA> name1 = new List<objA>() { new objA { foo1 = 1, foo2 = "bb", foo3 = true }, new objA { foo1 = 2, foo2 = "cc", foo3 = false } };
List<objA> name2 = new List<objA>();
List<objA> name3 = new List<objA>() { new objA { foo1 = 1, foo2 = "bb", foo3 = true } };
List<objA> name4 = new List<objA>() { new objA { foo1 = 1, foo2 = "bb", foo3 = true }, new objA { foo1 = 2, foo2 = "cc", foo3 = false } };
List<objA> name5 = new List<objA>() { new objA { foo1 = 1, foo2 = "bb", foo3 = true } };
List<objA> x = name1
//.Intersect(name2)
.Intersect(name3)
.Intersect(name4)
.Intersect(name5)
.ToList();
}
}
}
在阅读了关于这个问题的其他答案的评论之后,也许我错过了部分要点 - 是否希望在执行&#34;交叉&#34;时有效地忽略空集?
如果是这样,那么你可以通过编写自己版本的&#34; Intersect&#34;来忽略空集 - 例如。
using System.Collections.Generic;
using System.Linq;
namespace StackOverflowAnswer
{
public struct objA
{
public int foo1 { get; set; }
public string foo2 { get; set; }
public bool foo3 { get; set; }
}
class Program
{
static void Main()
{
List<objA> name1 = new List<objA>() { new objA { foo1 = 1, foo2 = "bb", foo3 = true }, new objA { foo1 = 2, foo2 = "cc", foo3 = false } };
List<objA> name2 = new List<objA>();
List<objA> name3 = new List<objA>() { new objA { foo1 = 1, foo2 = "bb", foo3 = true } };
List<objA> name4 = new List<objA>() { new objA { foo1 = 1, foo2 = "bb", foo3 = true }, new objA { foo1 = 2, foo2 = "cc", foo3 = false } };
List<objA> name5 = new List<objA>() { new objA { foo1 = 1, foo2 = "bb", foo3 = true } };
List<objA> x = name1
.IntersectUnlessEmpty(name2)
.IntersectUnlessEmpty(name3)
.IntersectUnlessEmpty(name4)
.IntersectUnlessEmpty(name5)
.ToList();
}
}
public static class IEnumerableExtensions
{
public static IEnumerable<T> IntersectUnlessEmpty<T>(this IEnumerable<T> source, IEnumerable<T> second)
{
return second.Any() ? source.Intersect(second) : source;
}
}
}
决赛&#34; x&#34;在这种情况下,值仍然是一个包含单个项目的列表 - 空的&#34; name2&#34;数据并不能阻止非空列表相互交叉。
答案 3 :(得分:-1)
以同样的方式:
public IEnumerable<T> IntersectsNonEmpty<T>(
params IEnumerable<T>[] input)
{
var nonEmpty = input.Where(i => i.Any()).ToList();
if (!nonEmpty.Any()) return false; //or whatever
return nonEmpty.Aggregate((l1, l2) => l1.Intersect(l2));
}
用法:
List<objA> result = IntersectsNonEmpty(name1, name2, name3, name4 .. and go on)
请注意,objA
应该覆盖Equals
,以便考虑具有相同字段值的不同实例:
public class objA
{
public override bool Equals(object other)
{
// impl
}
}
答案 4 :(得分:-1)
结果为空的原因是name2列表为空。如果在name2中添加{1,&#34; bb&#34;,true},则结果不会为空。