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>の両方から同じ結果が得られます。UnionConcat

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

Union は値を返しDistinctます。デフォルトでは、アイテムの参照を比較します。あなたのアイテムは異なる参照を持っているため、それらはすべて異なるものと見なされます。base type にキャストすると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文字どおり、最初のシーケンスの項目と、それに続く 2 番目のシーケンスの項目を返します。Concat2 つの 2 アイテム シーケンスで使用すると、常に 4 アイテム シーケンスが得られます。

Union基本的Concatに が続きDistinctます。

最初の 2 つのケースでは、入力シーケンスの各ペアが正確に 2 つの異なる項目を持つため、最終的に 2 項目のシーケンスになります。

3 番目のケースでは、2 つの入力シーケンスの 4 つの項目すべてが異なるため、最終的に 4 項目のシーケンスになります

于 2012-11-16T13:29:53.323 に答える
18

Unionカスタムなしでは重複を検出できないためConcat、同じように動作します。両方が同じ参照であるかどうかを調べているだけです。UnionIEqualityComparer<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 に答える