オブジェクトのリストから個別のフィールド値を返すlinqクエリ


91
class obj
{
    int typeId; //10 types  0-9 
    string uniqueString; //this is unique
}

objの要素が100個あるリストがありますが、一意のtypeIDは10個だけであると想定します。
オブジェクトのリストから10個の一意のintを返すLINQクエリを作成することは可能ですか?


この質問はとても簡単で、賞金には合いません。
思想家

回答:


157
objList.Select(o=>o.typeId).Distinct()

2
2番目の形式は、私が知る限り存在しないDistinctのオーバーロードを使用しているようです。
Jon Skeet 2011年

おっと、2番目のものを削除しました。@ JonSkeetに感謝します。これは、IEqualityComparer
Arsen Mkrtchyan

3
Jon Skeetが述べたように、これはSelectで指定されたプロパティのみを返します。
Peet vd Westhuizen 2016年

59

完全なオブジェクトが必要であるがtypeID、によって区別を処理するだけであると仮定すると、これを簡単にするためにLINQに組み込まれているものはありません。(値だけが必要な場合はtypeID、簡単です。でそれに投影してからSelect、通常のDistinct呼び出しを使用します。)

MoreLINQ我々はDistinctByあなたが使用できる演算子を:

var distinct = list.DistinctBy(x => x.typeID);

ただし、これはLINQ toObjectsでのみ機能します。

グループ化またはルックアップを使用できますが、これはやや面倒で非効率的です。

var distinct = list.GroupBy(x => x.typeID, (key, group) => group.First());

DistinctByを表示するには、名前空間Microsoft.Ajax.Utilities
Shiljo Paulson 2016

1
@Shil:いいえ、MoreLINQでDistinctByについて書いていました。Microsoft.Ajax.Utilitiesとは何の関係もありません。
Jon Skeet 2016

これで、LINQにDistinctのオーバーロードがあり、IEqualityComparerをパラメーターとして受け取り、IEqualityComparerのメソッドの実装に応じて個別のオブジェクトのリストを返すことがわかります
DipenduPaul19年

1
@DipenduPaul:はい。ただし、それでも、特定のプロパティの等式比較子を作成することを意味します。これは煩わしく、読みにくくなります。MoreLINQの依存関係を取ることができれば、それはよりクリーンだと思います。
JonSkeet19年

26

純粋なLinqを使用したいだけの場合は、groupbyを使用できます。

List<obj> distinct =
  objs.GroupBy(car => car.typeID).Select(g => g.First()).ToList();

MoreLinqと同様に、アプリ全体でメソッドを使用する場合は、次のようにします。

public static IEnumerable<TSource> DistinctBy<TSource, TKey>
    (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
    HashSet<TKey> seenKeys = new HashSet<TKey>();
    foreach (TSource element in source)
    {
        if (!seenKeys.Contains(keySelector(element)))
        {
            seenKeys.Add(keySelector(element));
            yield return element;
        }
    }
}

このメソッドを使用して、Idプロパティのみを使用して個別の値を見つけるには、次を使用できます。

var query = objs.DistinctBy(p => p.TypeId);

複数のプロパティを使用できます。

var query = objs.DistinctBy(p => new { p.TypeId, p.Name });

複数のプロパティの部分をありがとう!
NAE

7

確かに、を使用してくださいEnumerable.Distinct

obj(eg foo)のコレクションが与えられた場合、次のようにします。

var distinctTypeIDs = foo.Select(x => x.typeID).Distinct();

5

私はこれがあなたが探しているものだと思います:

    var objs= (from c in List_Objects 
orderby c.TypeID  select c).GroupBy(g=>g.TypeID).Select(x=>x.FirstOrDefault());      

これと同様に、LINQで個別のIQueryableを返しますか?


.First何かがなければグループは存在しないので、問題ありません。
mqp 2011年

1
の代替オーバーロードを使用して、GroupByこれも簡単にすることができます-例については私の答えを参照してください。
Jon Skeet 2011年

3

ただのLINQを使用する場合は、上書きすることができますのEqualsGetHashCodeメソッドのメソッドを。

製品クラス:

public class Product
{
    public string ProductName { get; set; }
    public int Id { get; set; }


    public override bool Equals(object obj)
    {
        if (!(obj is Product))
        {
            return false;
        }

        var other = (Product)obj;
        return Id == other.Id;
    }

    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }
}

主な方法:

static void Main(string[] args)
    {

        var products = new List<Product>
        {
            new Product{ ProductName="Product 1",Id = 1},
            new Product{ ProductName="Product 2",Id = 2},
            new Product{ ProductName="Product 4",Id = 5},
            new Product{ ProductName="Product 3",Id = 3},
            new Product{ ProductName="Product 4",Id = 4},
            new Product{ ProductName="Product 6",Id = 4},
            new Product{ ProductName="Product 6",Id = 4},
        };

        var itemsDistinctByProductName = products.Distinct().ToList();

        foreach (var product in itemsDistinctByProductName)
        {
            Console.WriteLine($"Product Id : {product.Id} ProductName : {product.ProductName} ");
        }

        Console.ReadKey();
    }

1

特定のデータをドロップダウンにバインドしたかったのですが、それは明確である必要があります。私は次のことをしました:

List<ClassDetails> classDetails;
List<string> classDetailsData = classDetails.Select(dt => dt.Data).Distinct.ToList();
ddlData.DataSource = classDetailsData;
ddlData.Databind();

それが役立つかどうかを確認する

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