linqを使用してリストの重複を削除する


314

のクラスItemsがありproperties (Id, Name, Code, Price)ます。

のリストにItems重複したアイテムが入力されています。

例:

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

linqを使用してリスト内の重複を削除する方法は?


アイテムクラスにもプロパティとして別のクラスがあります
プラサード

あなたも行うことができますvar set = new HashSet<int>(); var uniques = items.Where(x => set.Add(x.Id));。...そうする犯罪者でなければなりません
nawfal

回答:


394
var distinctItems = items.Distinct();

一部のプロパティのみを照合するには、次のようにカスタムの等値比較子を作成します。

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

次に、次のように使用します。

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

こんにちはクリスチャン、List <my_Custom_Class>とList <string>がある場合、コードはどのように変わりますか?カスタムクラスにはさまざまなアイテムがあり、そのうちの1つはDCN番号で、list <string>はDCN番号のみです。そのため、List <Custom_Class>にList <string>のdcnが含まれていることを確認する必要があります。たとえば、List1 = List <Custom_Class>およびList2 = List <String>であるとします。List1に2000個のアイテムがあり、list2に40000個のアイテムがあり、List1の600個のアイテムがList2に存在する場合。したがって、この場合、list1として出力リストとして1400が必要です。それで、表現はどうなるでしょう。よろしく

また、List1にはさまざまなアイテムが含まれているため、もう1つのケースがあります。他のアイテムの値は異なる場合がありますが、DCNは同じである必要があります。したがって、私の場合、Distinctは望ましい出力を提供できませんでした。

2
比較クラスは非常に便利です。単純なプロパティ名の比較以外のロジックを表現できます。先月、GroupByできなかったことをするために新しいものを書きました。
Christian Hayter 2013

うまく機能し、新しいことを学び、C#でXoRオペレーターを調査するようになりました^。VB.NETを介して使用しXorていましたが、最初は何であるかを確認するためにコードをダブルテイクする必要がありました。
atconway 2014年

これは、Distinct Comparerを使用しようとすると発生するエラーです。「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]) 'メソッドであり、このメソッドはストア式に変換できません
user8128167

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

28
おかげで-比較クラスを作成しないようにしていたので、この作業がうれしいです:)
Jen

8
+1このソリューションはタイブレーカーを可能にします:基準で重複を排除します!
アドリアーノカルネイロ2013

4
しかし、少しオーバーヘッド!
Amirhossein Mehrvarzi 2014年

1
しかし、Victor Juriが以下に提案したように:FirstorDefaultを使用します。信じられない、その解決策はとても簡単である(カスタムの等値比較器なし)
Cyber​​Hawk

6
複数のプロパティでグループ化できます:List <XYZ> MyUniqueList = MyList.GroupBy(x => new {x.Column1、x.Column2})。Select(g => g.First())。ToList();
Sumit Joshi

41

Distinctクエリをスローしているものがある場合は、MoreLinqを調べてDistinctBy演算子を使用し、IDで個別のオブジェクトを選択することができます。

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

1
LinqにはDistinctBy()メソッドはありません。
Fereydoon Barikzehy 2016年

7
@FereydoonBarikzehyしかし、彼は純粋なLinqについて話していません。MoreLinqプロジェクトのlinqがポストされています...
Ademar

30

これが私がLinqとグループ化する方法でした。それが役に立てば幸い。

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

3
@ nawfal、First()の代わりにFirstOrDefault()を提案していた
sobelito 2014年

23
私が正しい場合、空のグループが存在する可能性がないため、FirstOrDefaultここを使用してもSelectすぐに次の場合はメリットGroupByがありません(グループはコレクションのコンテンツから派生したものです)
Roy Tinker

17

使用しますDistinct()が、デフォルトの等値比較演算子を使用して値を比較するため、それ以外のものが必要な場合は、独自の比較演算子を実装する必要があります。

例については、http://msdn.microsoft.com/en-us/library/bb348436.aspxを参照してください


コレクションメンバーの型が値の型の1つである場合、デフォルトの比較子が機能することに注意してください。しかし、参照型に対してcscで選択するデフォルトの等値比較子。参照型には独自の比較演算子が必要です。
Nuri YILMAZ 2017

16

リストから重複したアイテムを削除するには、3つのオプションがあります。

  1. カスタムの等値比較子を使用してからDistinct(new DistinctItemComparer())@ Christian Hayterが言及したように使用します。
  2. を使用GroupByGroupByますが、すべての列でグループ化する必要があることに注意してください。グループ化しただけIdでは、重複する項目が常に削除されるわけではありません。たとえば、次の例を考えてみます。

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

    このグループ化の結果は次のようになります。

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

    {Id = 3, Name = "Item3", Code = "IT00004", Price = 250}重複と見なされるため、これは誤りです。したがって、正しいクエリは次のようになります。

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

    3.オーバーライドEqualしてGetHashCode、アイテムクラス内:

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

    その後、次のように使用できます。

    var distinctItems = a.Distinct();

11

普遍的な拡張方法:

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

使用例:

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

非常にクリーンなアプローチ
スティーブンリサート

4

この拡張メソッドを試してみてください。うまくいけば、これが役立つかもしれません。

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

使用法:

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

もう1つの回避策は、美しくなく実行可能な購入です。

RAMモジュール情報を記録するために、「GRADE」と「SPD」の2つの属性を持つ「MEMDES」と呼ばれる要素を持つXMLファイルがあります。SPDには重複アイテムがたくさんあります。

だからここに私が重複したアイテムを削除するために使用するコードです:

        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を記述したくない場合は、次のようなことを試すことができます。

 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; }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.