95

我有一个关于Union和的问题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>我从Union和得到相同结果的情况下Concat

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>.

请问有什么建议吗?

4

3 回答 3

121

联合返回Distinct值。默认情况下,它将比较项目的引用。您的项目有不同的参考,因此它们都被认为是不同的。当您转换为基本类型X时,引用不会更改。

如果您将覆盖Equalsand GetHashCode(用于选择不同的项目),则项目将不会通过引用进行比较:

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

您的初始示例有效,因为整数是值类型,并且它们按值进行比较。

于 2012-11-16T13:29:04.487 回答
55

Concat从字面上返回第一个序列中的项目,然后是第二个序列中的项目。如果您Concat在两个 2 项序列上使用,您将始终得到一个 4 项序列。

Union本质上ConcatDistinct.

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

在您的第三种情况下,您最终得到一个 4 项序列,因为您的两个输入序列中的所有四个项都是 distinct

于 2012-11-16T13:29:53.323 回答
18

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()); 
于 2012-11-16T13:32:03.263 回答