2012-11-16 124 views
55

我对UnionConcat有疑问。我猜两者在List<T>的情况下表现相同。Linq联盟VS Concat

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>

有什么建议吗?

+1

如果你知道这两种方法之间的差别,为什么结果令你感到惊讶?这是方法功能的直接结果。 –

+0

@KonradRudolph,我的意思是列入名单我可以使用任何一个'Union'/'Concat'。因为两者行为相同。 –

+0

不,显然不是。你的第一个例子表明它们的行为不一样。 –

回答

68

联盟返回Distinct值。默认情况下,它会比较项目的引用。你的物品有不同的参考,因此他们都被认为是不同的。当您投射到基本类型X时,引用不会更改。

如果你将覆盖EqualsGetHashCode(用来选择不同的项目),则项目将不会被引用进行比较:

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几个项目,那么你将看到差异UnionConcat之间:

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 

您最初的样本工程,因为整数是值类型,它们按值进行比较。

+2

即使它没有比较引用,但例如由于ID不同,所以仍然有四个项目。 – Rawling

+0

@Rawling同意,也是真的 –

+0

@Swani nope,他们不是。我想你没有改变第二集合中第一个项目的ID,正如我上面所述 –

29

Concat从字面上返回来自第一个序列的项目,然后从第二个序列返回项目。如果对两个2项目序列使用Concat,则总是会得到4项目序列。

Union本质上是Concat其次是Distinct

在你的前两种情况下,你最终得到2项目序列,因为在它们之间,每对输入序列都有两个不同的项目。

在第三种情况下,由于两个输入序列中的所有四个项目都是不同的,所以最终得到4项目序列。

12

UnionConcat表现相同,因为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());