Saya memiliki pertanyaan tentang Union
dan Concat
. Saya kira keduanya berperilaku sama dalam kasus 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"
Hasil di atas diharapkan,
Tapi Memetikan List<T>
saya mendapatkan hasil yang sama.
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
Tapi keduanya berperilaku sama List<T>
.
Ada saran, tolong?
Jawaban:
Union mengembalikan
Distinct
nilai. Secara default akan membandingkan referensi item. Item Anda memiliki referensi yang berbeda, sehingga semuanya dianggap berbeda. Saat Anda mentransmisikan ke tipe dasarX
, referensi tidak berubah.Jika Anda akan menimpa
Equals
danGetHashCode
(digunakan untuk memilih item yang berbeda), maka item tidak akan dibandingkan dengan referensi: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(); } }
Tetapi semua item Anda memiliki nilai yang berbeda
ID
. Jadi semua item masih dianggap berbeda. Jika Anda akan memberikan beberapa item dengan yang samaID
maka Anda akan melihat perbedaan antaraUnion
danConcat
: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
Sampel awal Anda berfungsi, karena bilangan bulat adalah jenis nilai dan dibandingkan berdasarkan nilai.
sumber
x.Union(y)
sama denganx.Concat(y).Distinct()
. Jadi bedanya hanya dengan melamarDistinct
. Bagaimana Linq memilih objek yang berbeda (yaitu yang berbeda) dalam urutan yang digabungkan? Dalam kode sampel Anda (dari pertanyaan) Linq membandingkan objek dengan referensi (yaitu alamat dalam memori). Ketika Anda membuat objek baru melaluinew
operator, itu mengalokasikan memori di alamat baru. Jadi, ketika Anda memiliki empat objek yang baru dibuat, alamatnya akan berbeda. Dan semua objek akan berbeda. Dengan demikianDistinct
akan mengembalikan semua objek dari urutan.Concat
secara harfiah mengembalikan item dari urutan pertama diikuti dengan item dari urutan kedua. Jika Anda menggunakanConcat
dua urutan 2 item, Anda akan selalu mendapatkan urutan 4 item.Union
pada dasarnyaConcat
diikuti olehDistinct
.Dalam dua kasus pertama, Anda akan mendapatkan urutan 2 item karena, di antara keduanya, setiap pasangan kotak masukan memiliki tepat dua item yang berbeda.
Dalam kasus ketiga Anda, Anda berakhir dengan urutan 4 item karena keempat item dalam dua urutan masukan Anda berbeda .
sumber
Union
danConcat
berperilaku sama karenaUnion
tidak dapat mendeteksi duplikat tanpa kebiasaanIEqualityComparer<X>
. Hanya melihat jika keduanya adalah referensi yang sama.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(); } }
Sekarang Anda dapat menggunakannya dalam kelebihan beban
Union
:var comparer = new XComparer(); a5 = lstX1.Cast<X>().Union(lstX2.Cast<X>(), new XComparer());
sumber