web-dev-qa-db-ja.com

LINQを使用したアイテムの一意のリスト

私は今しばらくLINQを使用していますが、ユニークアイテムに関して何かに行き詰まっているようです。次のリストがあります。

List<Stock> stock = new List<Stock>();

これには次のプロパティがあります:文字列ID、文字列タイプ、文字列説明、例:

public class Stock
{
    public string ID { get; set; }
    public string Type { get; set; }
    public string Description { get; set; }
}

在庫のアイテムをタイプ別にグループ化し、これを新しい在庫リストとして返すLINQクエリが必要です(元の在庫リストと同じタイプである必要があります)。

データの例:

 ID   Type                 Description
----------------------------------------------
  1   Kitchen Appliance    Dishwasher  
  2   Living Room          Television  
  3   Kitchen Appliance    Washing Machine  
  4   Kitchen Appliance    Fridge  

...

私のLinqクエリは、例としてすべてのキッチンアプライアンスを返すことができるようにしたいと考えています。
したがって、これを「タイプ」としてクエリに渡し、この例のリストからアイテム1、3、4を返します。

返されるこのリストもList<Stock>タイプである必要があります。

基本的に、SQL Distinctクエリのような種類ごとの一意の項目のリストが必要です。これをLINQで実現するにはどうすればよいですか?
代替ソリューションは問題ありませんが、Silverlight/C#クライアントコードのみである必要があります。

もう1つの明確化は、パラメーター「キッチンアプライアンス」も提供せず、ユニークなものだけが必要な場合があることです。たとえば、キッチンアプライアンスとリビングルームは、そのタイプの数に関係なく、カテゴリのようなものに1回だけ返されます。がある。

20
RoguePlanetoid

柔軟なアプローチ

GroupByToDictionary を使用して、TypeプロパティをキーとするList<Stock>値の辞書を作成します。

var appliancesByType = stock
    .GroupBy(item => item.Type)
    .ToDictionary(grp => grp.Key, grp => grp.ToList());

そうすれば、特定のタイプのリストだけでなく、タイプ自体にも非常に簡単にアクセスできます。

// List of unique type names only
List<string> stockTypes = appliancesByType.Keys.ToList();

// Or: list of one stock item per type
List<Stock> exampleStocks = appliancesByType
    .Select(kvp => kvp.Value[0])
    .ToList();

// List of stock items for a given type
List<Stock> kitchenAppliances = appliancesByType["Kitchen Appliance"];

このアプローチは、私が見ているように、実際にすべてのニーズを処理します。ただし、他のいくつかのオプションについては、以下を参照してください。

代替(迅速かつダーティー)なアプローチ

常に Where を使用して必要なタイプのアイテムを取得し、次に ToList を使用してこれらのアイテムを新しいList<Stock>

List<Stock> kitchenAppliances = stock
    .Where(item => item.Type == "Kitchen Appliance")
    .ToList();

この最後の部分への応答:

もう1つの明確化は、パラメーター「キッチンアプライアンス」も提供せず、ユニークなものだけが必要な場合があることです。たとえば、キッチンアプライアンスとリビングルームは、そのタイプの数に関係なく、カテゴリのようなものに1回だけ返されます。がある。

ここでは、完全に異なるものを望んでいるようです:基本的に Distinct によって提供される動作。この機能については、基本的に Soontsの回答 を使用できます(オプションで、IEnumerable<tKey>ではなくIEnumerable<tSource>を返します)、またはDistinctを組み合わせて使用​​することもできます Select を使用すると、IEqualityComparer<Stock>を実装する必要がなくなります(以下を参照)。


更新

あなたの明確化に応えて、これが私の推奨です:各目的に1つずつの2つの方法( 単一の責任の原則 ):

// This will return a list of all Stock objects having the specified Type
static List<Stock> GetItemsForType(string type)
{
    return stock
        .Where(item => item.Type == type)
        .ToList();
}

// This will return a list of the names of all Type values (no duplicates)
static List<string> GetStockTypes()
{
    return stock
        .Select(item => item.Type)
        .Distinct()
        .ToList();
}
45
Dan Tao

必要な単純なWhere句のように聞こえます。

_List<Stock> kitchen= stock.Where(s=>s.Type=="Kitchen Appliance")
                          .OrderBy(s=>s.Description).ToList();
_

厳密にソースリストに含まれるTypesが必要な場合:

string[] typesFound = stock.Select(s=>s.Type).Distinct().ToArray();

4
p.campbell
static class EnumerableEx
{
    // Selectively skip some elements from the input sequence based on their key uniqueness.
    // If several elements share the same key value, skip all but the 1-st one.
    public static IEnumerable<tSource> uniqueBy<tSource, tKey>( this IEnumerable<tSource> src, Func<tSource, tKey> keySelecta )
    {
        HashSet<tKey> res = new HashSet<tKey>();
        foreach( tSource e in src )
        {
            tKey k = keySelecta( e );
            if( res.Contains( k ) )
                continue;
            res.Add( k );
            yield return e;
        }
    }
}

// Then later in the code
List<Stock> res = src.uniqueBy( elt => elt.Type ).ToList()
3
Soonts
var kitchenAppliances = stocks.Where(stock => stock.Type == "Kitchen Appliance");
3

これらの線に沿って何かを実行することもできます。この場合、私はルセンの結果を取得してから、umbracoノードを匿名型にプルオフします

var datasource = (from n in SearchResults
select new
{
  PageLink = uQuery.GetNode(n.Id).NiceUrl,
  uQuery.GetNode(n.Id).Name,
  Date =    uQuery.GetNode(n.Id).GetProperty("startDate"),
  IntroText = string.IsNullOrEmpty(uQuery.GetNode(n.Id).GetProperty("introText").Value) ? string.Empty : uQuery.GetNode(n.Id).GetProperty("introText").Value,
  Image = ImageCheck(uQuery.GetNode(n.Id).GetProperty("smallImage").Value)

}).Distinct().ToList();
1
Netferret

私はおそらく質問を理解していませんが、これは非常に単純なLinqクエリのように聞こえます。

List<Stock> stock = new List<Stock>();
... populate your list as per your example

List<Stock> kitchenAppliances =
    (from obj in stock
     where obj.Type == "Kitchen Appliance"
     select obj).ToList();

または、拡張メソッドの構文を使用する場合:

List<Stock> kitchenAppliances =
    stock.Where(obj => obj.Type == "Kitchen Appliance").ToList();

私が理解していないのは、この文脈での明確でユニークなあなたの使用法です。オブジェクトは既に一意であり、「すべての台所用品をください」という基本的なクエリが必要なようです。