在Linq的Union Vs Concat
我有一个关于Union
和Concat
的问题。 我猜在List<T>
情况下,两者的行为都是一样的。
var a1 = (new[] { 1, 2 }).Union(new[] { 1, 2 }); // O/P : 1 2 var a2 = (new[] { 1, 2 }).Concat(new[] { 1, 2 }); // O/P : 1 2 1 2 var a3 = (new[] { "1", "2" }).Union(new[] { "1", "2" }); // O/P : "1" "2" var a4 = (new[] { "1", "2" }).Concat(new[] { "1", "2" }); // O/P : "1" "2" "1" "2"
以上结果是可以预料的,
但是List<T>
我得到了同样的结果。
class X { public int ID { get; set; } } class X1 : X { public int ID1 { get; set; } } class X2 : X { public int ID2 { get; set; } } var lstX1 = new List<X1> { new X1 { ID = 10, ID1 = 10 }, new X1 { ID = 10, ID1 = 10 } }; var lstX2 = new List<X2> { new X2 { ID = 10, ID2 = 10 }, new X2 { ID = 10, ID2 = 10 } }; var a5 = lstX1.Cast<X>().Union(lstX2.Cast<X>()); // O/P : a5.Count() = 4 var a6 = lstX1.Cast<X>().Concat(lstX2.Cast<X>()); // O/P : a6.Count() = 4
但是这两个行为都与List<T>
。
有什么build议吗?
联盟返回Distinct
值。 默认情况下,它会比较项目的引用。 你的物品有不同的参考,因此他们都被认为是不同的。 当您转换为基本typesX
,引用不会更改。
如果您将覆盖Equals
和GetHashCode
(用于select不同的项目),则不会通过引用来比较项目:
class X { public int ID { get; set; } public override bool Equals(object obj) { X x = obj as X; if (x == null) return false; return x.ID == ID; } public override int GetHashCode() { return ID.GetHashCode(); } }
但是所有的物品都有不同的ID
值。 所以所有项目仍然被认为是不同 如果您将提供具有相同ID
多个项目,那么您将看到Union
和Concat
之间的区别:
var lstX1 = new List<X1> { new X1 { ID = 1, ID1 = 10 }, new X1 { ID = 10, ID1 = 100 } }; var lstX2 = new List<X2> { new X2 { ID = 1, ID2 = 20 }, // ID changed here new X2 { ID = 20, ID2 = 200 } }; var a5 = lstX1.Cast<X>().Union(lstX2.Cast<X>()); // 3 distinct items var a6 = lstX1.Cast<X>().Concat(lstX2.Cast<X>()); // 4
你的初始样本工作,因为整数是值types,他们进行比较的价值。
Concat
从字面上返回第一个序列中的项目,然后是第二个序列中的项目。 如果你在两个2项目序列上使用Concat
,你将总是得到一个4项目序列。
Union
基本上是Concat
其次是Distinct
。
在前两种情况下,最终会产生2个项目的序列,因为在它们之间,每对input序列只有两个不同的项目。
在第三种情况下,由于两个input序列中的所有四个项目都是不同的 ,所以最终得到一个4项目序列。
Union
和Concat
行为相同,因为Union
无法在没有自定义IEqualityComparer<X>
情况下检测到重复项。 这只是看,如果两者是相同的参考。
public class XComparer: IEqualityComparer<X> { public bool Equals(X x1, X x2) { if (object.ReferenceEquals(x1, x2)) return true; if (x1 == null || x2 == null) return false; return x1.ID.Equals(x2.ID); } public int GetHashCode(X x) { return x.ID.GetHashCode(); } }
现在你可以在Union
的重载中使用它:
var comparer = new XComparer(); a5 = lstX1.Cast<X>().Union(lstX2.Cast<X>(), new XComparer());