web-dev-qa-db-ja.com

linqを使ってリストから重複を取り除く

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

Itemsのリストに重複した項目が表示されます。

例:

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

Linqを使ってリスト内の重複を削除するにはどうすればいいですか?

265
Prasad
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());
350
var distinctItems = items.GroupBy(x => x.Id).Select(y => y.First());
540
Freddy

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

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

これが私がLinqとグループを組むことができた方法です。それが役に立てば幸い。

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

Distinct()を使いますが、それは値を比較するためにデフォルトの等値比較子を使うことを覚えておいてください。

例については、 http://msdn.Microsoft.com/ja-jp/library/bb348436.aspx を参照してください。

16
Brian Rasmussen

あなたのリストから重複したアイテムを削除するには3つの方法があります。

  1. カスタム等価比較子を使用してから、Distinct(new DistinctItemComparer())@ Christian Hayter のように使用します。
  2. GroupByを使用しますが、GroupByでは、すべての列でグループ化する必要があります。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.アイテムクラスでEqualGetHashCodeをオーバーライドします。

    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();
    
12
Salah Akbari

普遍的な拡張方法

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(g => g.Key);
5
TOL
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();
3
Arun Kumar

この拡張方法を試してみてください。うまくいけば、これは役立つかもしれません。

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
Kent Aguilar

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; }
}
0
Kundan Bhati