Linq'te Union Vs Concat


86

Ben bir sorum var Unionve Concat. Sanırım her ikisi de aynı şekilde davranıyor 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"

Yukarıdaki sonuç bekleniyor,

Ama List<T>ben de aynı sonucu alıyorum.

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

Ama ikisi de aynı durumda davranıyor List<T>.

Herhangi bir öneri lütfen?


1
Bu iki yöntem arasındaki farkı biliyorsanız, sonuç sizi neden şaşırttı? Bu, yöntemlerin işlevselliğinin doğrudan bir sonucudur.
Konrad Rudolph

@KonradRudolph, Demek istediğim List <T> herhangi bir 'Union' / 'Concat' kullanabilirim. Çünkü ikisi de aynı şekilde davranıyor.
Prasad Kanaparthi

Hayır, belli ki hayır. İlk örneğinizin gösterdiği gibi aynı davranmazlar.
Konrad Rudolph

Örneğinizde tüm kimlikler farklıdır.
Jim Mischel

@JimMischel, yazımı düzenledi. aynı değerlerle bile aynı davranıyor.
Prasad Kanaparthi

Yanıtlar:


110

Birlik Distinctdeğerleri döndürür . Varsayılan olarak, öğelerin referanslarını karşılaştıracaktır. Öğelerinizin farklı referansları vardır, bu nedenle hepsi farklı kabul edilir. Temel türe Xçevirdiğinizde referans değişmez.

EqualsVe GetHashCode(farklı öğeleri seçmek için kullanılır) geçersiz kılarsanız , öğeler referansla karşılaştırılmayacaktır:

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();
    }
}

Ancak tüm öğelerinizin farklı değeri var ID. Yani tüm öğeler hala farklı kabul edildi. Aynı olan birkaç öğe IDsunacaksanız, Unionve arasında fark göreceksiniz 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

İlk örneğiniz çalışır, çünkü tamsayılar değer türleridir ve değere göre karşılaştırılırlar.


3
Referansları karşılaştırmasa bile, örneğin içindeki kimlikler olsa bile, kimlikler farklı olduğu için hala dört öğe olacaktır.
Rawling

@Swani hayır, onlar değil. Yukarıda belirttiğim gibi, ikinci koleksiyondaki ilk ürünün kimliğini değiştirmediğini düşünüyorum
Sergey Berezovskiy

@Swani, bu durumda yukarıda belirttiğim gibi Eşittir ve GetHashCode'u geçersiz kılmadınız
Sergey Berezovskiy

@lazyberezovsky, cevabınıza katılıyorum. Ancak yorumlardan hala memnun değilim. Örnek kodumu çalıştırırsanız, aynı sonucu 'a5' ve 'a6' için görebilirsiniz. Ben çözüm aramıyorum. Ama neden "Concat" ve "Union" bu durumda aynı davranıyor? Lütfen cevap verin.
Prasad Kanaparthi

3
@Swani üzgünüm, afk oldu. x.Union(y)ile aynıdır x.Concat(y).Distinct(). Yani fark sadece başvuruda Distinct. Linq birleştirilmiş dizilerde farklı (yani farklı) nesneleri nasıl seçer? Örnek kodunuzda (sorudan) Linq nesneleri referansa göre karşılaştırır (yani bellekteki adres). newOperatör aracılığıyla yeni nesne oluşturduğunuzda , yeni adrese bellek ayırır. Dolayısıyla, dört yeni oluşturulmuş nesneniz olduğunda, adresler farklı olacaktır. Ve tüm nesneler farklı olacaktır. Böylece Distincttüm nesneleri sırayla döndürür.
Sergey Berezovskiy

48

Concatkelimenin tam anlamıyla birinci dizideki öğeleri ve ardından ikinci dizideki öğeleri döndürür. Eğer kullanırsanız Concatiki 2 maddelik dizileri üzerinde, her zaman bir 4 maddelik dizisini alacak.

Uniontemelde Concatbunu takip eder Distinct.

İlk iki durumunuzda, 2 öğeli diziler elde edersiniz, çünkü aralarında, her girdi karesi çifti tam olarak iki farklı öğeye sahiptir.

Üçüncü durumunuzda, iki giriş dizinizdeki dört öğenin tümü farklı olduğu için 4 öğelik bir dizi ile sonuçlanırsınız .


14

Unionve bir gelenek olmadan kopyaları tespit edemediğinden Concataynı şekilde davranır . Sadece ikisinin de aynı referans olup olmadığına bakıyor.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();
    }
}

Şimdi onu aşağıdakilerin aşırı yüklenmesinde kullanabilirsiniz Union:

var comparer = new XComparer();
a5 = lstX1.Cast<X>().Union(lstX2.Cast<X>(), new XComparer()); 
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.