Hapus duplikat dalam daftar menggunakan LINQ

314

Saya memiliki kelas Itemsdengan properties (Id, Name, Code, Price).

Daftar Itemsdiisi dengan item duplikat.

Untuk ex .:

1         Item1       IT00001        $100
2         Item2       IT00002        $200
3         Item3       IT00003        $150
1         Item1       IT00001        $100
3         Item3       IT00003        $150

Bagaimana cara menghapus duplikat dalam daftar menggunakan LINQ?

Prasad
sumber
Saya memiliki kelas lain sebagai properti di Item Kelas juga
Prasad
Anda juga bisa melakukannya var set = new HashSet<int>(); var uniques = items.Where(x => set.Add(x.Id));. Seharusnya kriminal melakukannya ..
nawfal

Jawaban:

394
var distinctItems = items.Distinct();

Untuk mencocokkan hanya pada beberapa properti, buat pembanding kesetaraan khusus, misalnya:

class DistinctItemComparer : IEqualityComparer<Item> {

    public bool Equals(Item x, Item y) {
        return x.Id == y.Id &&
            x.Name == y.Name &&
            x.Code == y.Code &&
            x.Price == y.Price;
    }

    public int GetHashCode(Item obj) {
        return obj.Id.GetHashCode() ^
            obj.Name.GetHashCode() ^
            obj.Code.GetHashCode() ^
            obj.Price.GetHashCode();
    }
}

Kemudian gunakan seperti ini:

var distinctItems = items.Distinct(new DistinctItemComparer());
Christian Hayter
sumber
Hai Christian, Apa yang akan menjadi perubahan kode jika saya memiliki Daftar <my_Custom_Class> dan Daftar <string>. Kelas khusus saya memiliki berbagai item di mana satu adalah nomor DCN dan daftar <string> hanya memiliki nomor DCN. Jadi saya perlu memeriksa Daftar <Custom_Class> berisi dcn dari List <string>. Misalnya anggap List1 = Daftar <Custom_Class> dan List2 = Daftar <String>. Jika List1 memiliki 2000 item dan list2 memiliki 40000 item di mana 600 item dari List1 ada di List2. Jadi dalam hal ini saya perlu 1400 sebagai Daftar output saya sebagai list1. Jadi apa yang akan menjadi ungkapan. Terima kasih sebelumnya
Juga ada satu case lagi di sini karena List1 berisi berbagai item, nilai item lain mungkin berbeda tetapi DCN harus sama. Jadi dalam kasus saya Distinct gagal memberikan put yang diinginkan.
2
Saya menemukan kelas pembanding sangat berguna. Mereka dapat mengekspresikan logika selain dari perbandingan nama properti sederhana. Saya menulis yang baru bulan lalu, untuk melakukan sesuatu yang GroupBytidak bisa.
Christian Hayter
Bekerja dengan baik dan membuat saya mempelajari sesuatu yang baru dan menyelidiki XoRoperator ^di C #. Telah digunakan dalam VB.NET via Xortetapi harus melakukan double take untuk kode Anda untuk melihat apa itu pada awalnya.
atconway
Ini adalah kesalahan yang saya dapatkan ketika saya mencoba menggunakan Distinct Comparer: "LINQ to Entities tidak mengenali metode 'System.Linq.IQueryable 1[DataAccess.HR.Dao.CCS_LOCATION_TBL] Distinct[CCS_LOCATION_TBL](System.Linq.IQueryable1 [DataAccess.HR.Dao.CCS_LOCATION_TBL], System.Collections.Generic.IEqualityComparer`1 [ Metode DataAccess.HR.Dao.CCS_LOCATION_TBL]), dan metode ini tidak dapat diterjemahkan ke dalam ekspresi store
user8128167
601
var distinctItems = items.GroupBy(x => x.Id).Select(y => y.First());
Freddy
sumber
28
Terima kasih - ingin menghindari penulisan kelas pembanding jadi saya senang ini berhasil :)
Jen
8
+1 Solusi ini bahkan memungkinkan pengikat: hilangkan duplikat dengan kriteria!
Adriano Carneiro
4
Tapi sedikit overhead!
Amirhossein Mehrvarzi
1
Tapi, seperti yang disarankan Victor Juri di bawah ini: gunakan FirstorDefault. tidak percaya, solusi itu bisa sangat sederhana (tanpa
pembanding
6
Anda dapat mengelompokkan dengan beberapa properti: Daftar <XYZ> MyUniqueList = MyList.GroupBy (x => baru {x.Column1, x.Column2}). Pilih (g => g.First ()). ToList ();
Sumit Joshi
41

Jika ada sesuatu yang membuang kueri Distinct Anda, Anda mungkin ingin melihat MoreLinq dan menggunakan operator DistinctBy dan pilih objek yang berbeda dengan id.

var distinct = items.DistinctBy( i => i.Id );
tvanfosson
sumber
1
Tidak ada metode DistinctBy () dengan Linq.
Fereydoon Barikzehy
7
@FereydoonBarikzehy Tapi dia tidak berbicara tentang Linq murni. Dalam posting adalah linq untuk proyek MoreLinq ...
Ademar
30

Ini adalah bagaimana saya dapat dikelompokkan bersama dengan Linq. Semoga ini bisa membantu.

var query = collection.GroupBy(x => x.title).Select(y => y.FirstOrDefault());
Victor Juri
sumber
3
@nawfal, saya menyarankan FirstOrDefault () sebagai pengganti First ()
sobelito
23
Jika saya benar, menggunakan di FirstOrDefaultsini tidak memberikan manfaat jika Selectsegera diikuti GroupBy, karena tidak ada kemungkinan ada kelompok kosong (grup hanya berasal dari konten koleksi)
Roy Tinker
17

Gunakan Distinct()tetapi perlu diingat bahwa ia menggunakan pembanding kesetaraan default untuk membandingkan nilai, jadi jika Anda menginginkan sesuatu yang lebih dari itu, Anda perlu mengimplementasikan pembanding Anda sendiri.

Silakan lihat http://msdn.microsoft.com/en-us/library/bb348436.aspx untuk contoh.

Brian Rasmussen
sumber
Saya harus memperhatikan bahwa pembanding default berfungsi jika tipe anggota kumpulan adalah salah satu dari tipe nilai. Tetapi pembanding kesetaraan default mana yang dipilih oleh csc untuk jenis referensi. Jenis referensi harus memiliki pembanding sendiri.
Nuri YILMAZ
16

Anda memiliki tiga opsi di sini untuk menghapus item duplikat di Daftar Anda:

  1. Gunakan pembanding kesetaraan khusus dan kemudian gunakan Distinct(new DistinctItemComparer())seperti @Christian Hayter sebutkan.
  2. Gunakan GroupBy, tetapi harap dicatat bahwa GroupByAnda harus mengelompokkan semua kolom karena jika Anda hanya mengelompokkannya, Iditu tidak selalu menghapus item duplikat. Sebagai contoh, perhatikan contoh berikut:

    List<Item> a = new List<Item>
    {
        new Item {Id = 1, Name = "Item1", Code = "IT00001", Price = 100},
        new Item {Id = 2, Name = "Item2", Code = "IT00002", Price = 200},
        new Item {Id = 3, Name = "Item3", Code = "IT00003", Price = 150},
        new Item {Id = 1, Name = "Item1", Code = "IT00001", Price = 100},
        new Item {Id = 3, Name = "Item3", Code = "IT00003", Price = 150},
        new Item {Id = 3, Name = "Item3", Code = "IT00004", Price = 250}
    };
    var distinctItems = a.GroupBy(x => x.Id).Select(y => y.First());

    Hasil untuk pengelompokan ini adalah:

    {Id = 1, Name = "Item1", Code = "IT00001", Price = 100}
    {Id = 2, Name = "Item2", Code = "IT00002", Price = 200}
    {Id = 3, Name = "Item3", Code = "IT00003", Price = 150}

    Yang salah karena dianggap {Id = 3, Name = "Item3", Code = "IT00004", Price = 250}sebagai duplikat. Jadi permintaan yang benar adalah:

    var distinctItems = a.GroupBy(c => new { c.Id , c.Name , c.Code , c.Price})
                         .Select(c => c.First()).ToList();

    3.Override Equaldan GetHashCodedalam item kelas:

    public class Item
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Code { get; set; }
        public int Price { get; set; }
    
        public override bool Equals(object obj)
        {
            if (!(obj is Item))
                return false;
            Item p = (Item)obj;
            return (p.Id == Id && p.Name == Name && p.Code == Code && p.Price == Price);
        }
        public override int GetHashCode()
        {
            return String.Format("{0}|{1}|{2}|{3}", Id, Name, Code, Price).GetHashCode();
        }
    }

    Maka Anda dapat menggunakannya seperti ini:

    var distinctItems = a.Distinct();
Salah Akbari
sumber
12

Metode ekstensi universal:

public static class EnumerableExtensions
{
    public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> enumerable, Func<T, TKey> keySelector)
    {
        return enumerable.GroupBy(keySelector).Select(grp => grp.First());
    }
}

Contoh penggunaan:

var lstDst = lst.DistinctBy(item => item.Key);
TOL
sumber
Pendekatan yang sangat bersih
Steven Ryssaert
5

Coba metode ekstensi ini. Semoga ini bisa membantu.

public static class DistinctHelper
{
    public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
    {
        var identifiedKeys = new HashSet<TKey>();
        return source.Where(element => identifiedKeys.Add(keySelector(element)));
    }
}

Pemakaian:

var outputList = sourceList.DistinctBy(x => x.TargetProperty);
Kent Aguilar
sumber
3
List<Employee> employees = new List<Employee>()
{
    new Employee{Id =1,Name="AAAAA"}
    , new Employee{Id =2,Name="BBBBB"}
    , new Employee{Id =3,Name="AAAAA"}
    , new Employee{Id =4,Name="CCCCC"}
    , new Employee{Id =5,Name="AAAAA"}
};

List<Employee> duplicateEmployees = employees.Except(employees.GroupBy(i => i.Name)
                                             .Select(ss => ss.FirstOrDefault()))
                                            .ToList();
Arun Kumar
sumber
0

Solusi lain, beli tidak bisa dilakukan.

Saya memiliki file XML dengan elemen yang disebut "MEMDES" dengan dua atribut sebagai "GRADE" dan "SPD" untuk merekam informasi modul RAM. Ada banyak item dupelicate di SPD.

Jadi di sini adalah kode yang saya gunakan untuk menghapus item dupelicated:

        IEnumerable<XElement> MList =
            from RAMList in PREF.Descendants("MEMDES")
            where (string)RAMList.Attribute("GRADE") == "DDR4"
            select RAMList;

        List<string> sellist = new List<string>();

        foreach (var MEMList in MList)
        {
            sellist.Add((string)MEMList.Attribute("SPD").Value);
        }

        foreach (string slist in sellist.Distinct())
        {
            comboBox1.Items.Add(slist);
        }
Rex Hsu
sumber
-1

Ketika Anda tidak ingin menulis IEqualityComparer, Anda dapat mencoba sesuatu seperti mengikuti.

 class Program
{

    private static void Main(string[] args)
    {

        var items = new List<Item>();
        items.Add(new Item {Id = 1, Name = "Item1"});
        items.Add(new Item {Id = 2, Name = "Item2"});
        items.Add(new Item {Id = 3, Name = "Item3"});

        //Duplicate item
        items.Add(new Item {Id = 4, Name = "Item4"});
        //Duplicate item
        items.Add(new Item {Id = 2, Name = "Item2"});

        items.Add(new Item {Id = 3, Name = "Item3"});

        var res = items.Select(i => new {i.Id, i.Name})
            .Distinct().Select(x => new Item {Id = x.Id, Name = x.Name}).ToList();

        // now res contains distinct records
    }



}


public class Item
{
    public int Id { get; set; }

    public string Name { get; set; }
}
Kundan Bhati
sumber