Linq kullanarak listedeki kopyaları kaldırın


314

Birlikte bir dersim Itemsvar properties (Id, Name, Code, Price).

Listesi Itemsçoğaltılmış öğelerle doldurulur.

Örneğin:

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

Linq kullanarak listedeki kopyaları nasıl kaldırırım?


Ben de Öğeler Sınıfı mülkiyet olarak başka bir sınıf var
Prasad

Siz de yapabilirsiniz var set = new HashSet<int>(); var uniques = items.Where(x => set.Add(x.Id));. Bunu yapmak suç olmalı ..
nawfal

Yanıtlar:


394
var distinctItems = items.Distinct();

Bazı özelliklerle eşleşmek için özel bir eşitlik karşılaştırıcısı oluşturun, örn:

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

Sonra şu şekilde kullanın:

var distinctItems = items.Distinct(new DistinctItemComparer());

Merhaba Christian, Eğer bir List <my_Custom_Class> ve List <string> varsa kod değişikliği ne olacak. Özel sınıfımın DCN numarası ve <string> listesinin yalnızca DCN numarası olduğu çeşitli öğeleri var. Bu yüzden List <Custom_Class> List <string> 'den herhangi bir dcn içerip içermediğini kontrol etmem gerekiyor. Örneğin, List1 = List <Custom_Class> ve List2 = List <String> öğelerini varsayalım. Liste1'de 2000 öğe varsa ve liste2'de Liste2'de Liste1'den 600 öğe bulunan 40000 öğe varsa. Yani bu durumda benim liste olarak list1 olarak 1400 gerekir. Peki ifade ne olurdu. Şimdiden teşekkürler

Ayrıca, List1'de çeşitli öğeler bulunduğundan bir başka durum daha vardır, diğer öğe değerleri farklı olabilir, ancak DCN aynı olmalıdır. Yani benim durumumda Distinct istenen dışarı koymak veremedi.

2
Karşılaştırma sınıflarını son derece yararlı buluyorum. Basit özellik adı karşılaştırmaları dışında mantığı ifade edebilirler. Geçen ay yeni bir tane yazdım, yapamayacağım bir şey yapmak GroupByiçin.
Christian Hayter

İyi çalışıyor ve yeni bir şey öğrenmek ve C # XoRoperatörü araştırmak için beni getirdi ^. Üzerinden VB.NET kullanmıştı Xorama ilk başta ne olduğunu görmek için kodunuzu bir çift almak zorunda kaldı.
14'te

Farklı Karşılaştırıcı kullanmaya çalıştığımda aldığım hata: "LINQ to Entities '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 [ DataAccess.HR.Dao.CCS_LOCATION_TBL]) 'yöntemidir ve bu yöntem bir mağaza ifadesine
çevrilemez

601
var distinctItems = items.GroupBy(x => x.Id).Select(y => y.First());

28
Teşekkürler - bir karşılaştırma sınıfı yazmaktan kaçınmak istiyordu, bu yüzden bu işe sevindim :)
Jen

8
+1 Bu çözüm eşitlik kesiciye bile izin verir: yinelenenleri ölçütlerle ortadan kaldırın!
Adriano Carneiro

4
Ama biraz havai!
Amirhossein Mehrvarzi

1
Ancak, Victor Juri'nin aşağıda önerdiği gibi: FirstorDefault kullanın. inanamıyorum, bu çözüm çok basit olabilir (özel eşitlik karşılaştırıcısı olmadan)
CyberHawk

6
Birden çok özelliğe sahip gruplayabilirsiniz: Liste <XYZ> MyUniqueList = MyList.GroupBy (x => yeni {x.Column1, x.Column2}). (G => g.First ()). ToList ();
Sumit Joshi

41

Farklı sorgunuzu başlatan bir şey varsa, MoreLinq'e bakmak ve DistinctBy işlecini kullanmak ve kimliğe göre farklı nesneleri seçmek isteyebilirsiniz .

var distinct = items.DistinctBy( i => i.Id );

1
Linq ile DistinctBy () yöntemi yoktur.
Fereydoon Barikzehy

7
@FereydoonBarikzehy Ama saf Linq hakkında konuşmuyor. Post MoreLinq projesine linq olduğunu ...
Ademar

30

Linq ile gruplamayı böyle başardım. Umarım yardımcı olur.

var query = collection.GroupBy(x => x.title).Select(y => y.FirstOrDefault());

3
@nawfal, ben FirstOrDefault () yerine First () yerine
sobelito

23
Doğruysam, FirstOrDefaultburada kullanmak Selecthemen takip ederse hiçbir fayda sağlamaz GroupBy, çünkü boş bir grup olma olasılığı yoktur (gruplar sadece koleksiyonun içeriğinden türetilmiştir )
Roy Tinker

17

Distinct()Bunu kullanın, ancak değerleri karşılaştırmak için varsayılan eşitlik karşılaştırıcısını kullandığını unutmayın, bu yüzden bunun ötesinde bir şey istiyorsanız, kendi karşılaştırıcıyı uygulamanız gerekir.

Örnek için lütfen http://msdn.microsoft.com/tr-tr/library/bb348436.aspx adresine bakın .


Koleksiyon üye türleri değer türlerinden biri ise varsayılan karşılaştırıcı çalışır dikkat etmeliyim. Ancak hangi varsayılan eşitlik karşılaştırıcısı referans türleri için csc tarafından seçilir. Referans türlerinin kendi karşılaştırıcıları olmalıdır.
Nuri YILMAZ

16

Listenizdeki yinelenen öğeleri kaldırmak için üç seçeneğiniz vardır:

  1. Bir özel eşitlik karşılaştırıcısı kullanın ve daha sonra @Christian HayterDistinct(new DistinctItemComparer()) olarak kullanın .
  2. Kullanın GroupBy, ancak lütfen GroupBytüm sütunlara göre Gruplandırmanız gerektiğini unutmayın, çünkü yalnızca gruplandırırsanız Idyinelenen öğeleri her zaman kaldırmaz. Örneğin, aşağıdaki örneği ele alalım:

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

    Bu gruplamanın sonucu:

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

    Bu yanlış çünkü {Id = 3, Name = "Item3", Code = "IT00004", Price = 250}yineleniyor. Yani doğru sorgu:

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

    3.Override Equalve GetHashCodeöğe sınıfında:

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

    O zaman bu şekilde kullanabilirsiniz:

    var distinctItems = a.Distinct();

11

Evrensel bir genişletme yöntemi:

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

Kullanım örneği:

var lstDst = lst.DistinctBy(item => item.Key);

Çok temiz bir yaklaşım
Steven Ryssaert

4

Bu uzantı yöntemini deneyin. Umarım bu yardımcı olabilir.

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

Kullanımı:

var outputList = sourceList.DistinctBy(x => x.TargetProperty);

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

0

Başka bir çözüm, güzel değil uygulanabilir satın alın.

RAM modülü bilgilerini kaydetmek için "GRADE" ve "SPD" olarak iki özniteliği "MEMDES" adlı bir öğeye sahip bir XML dosyası var. SPD'de çok sayıda yinelenen öğe var.

Bu yüzden, yeniden çoğaltılmış öğeleri kaldırmak için kullandığım kod:

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

-1

IEqualityComparer yazmak istemediğinizde aşağıdaki gibi bir şey deneyebilirsiniz.

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