3
public class Item
{
    public int Id {get; set;}
    public bool Selected {get; set;}
}

List<Item> itemList = new List<Item>(){ /* fill with items */ };

次の条件を満たすアイテムのリストを作成する必要があります。から、アイテムをグループ化してから、各グループから1つのアイテムを選択するitemList必要があります。Id選択するアイテムは、Selected == true。グループ内のアイテムが選択されていない場合は、任意のアイテムを選択できます。問題はありませんが、1つを選択する必要があります。

この質問に基づく: LambdaまたはLINQによるリストから個別のインスタンスを取得する方法

私は以下をまとめることができました、それはうまくいくようです:

var distinctList = itemList.GroupBy(x => x.Id, 
    (key, group) => group.Any(x => x.Selected) ? 
        group.First(x => x.Selected) : group.First());

これを達成するためのより効率的またはより簡単な方法はありますか?試しFirstOrDefault()ましたが、必要なことを実行できなかったようです。上記のコードの効率に関する私の懸念は、Any()の呼び出しです。

4

3 に答える 3

3

確かにFirstOrDefault拡張メソッドを使用できますが、 predicate を取るバージョンを使用し、それを合体演算子 ( ??)と組み合わせます (簡単にするために、ここではクエリ構文を使用しました)。

var distinctList =
    from item in itemList
    group item by item.Id into g
    select g.FirstOrDefault(i => i.Selected) ?? g.First();

の述語を使用して、プロパティが trueFirstOrDefaultである最初の項目を選択しています。Selected何もない場合、型が参照型であると仮定すると (これは、これを使用することが重要ですFirstOrDefault)、 が返されnullます。

Firstnull が返された場合、任意のアイテムが返される可能性があり、アイテムが含まれていないグループは存在できないため、( への呼び出しを通じて)グループ内の最初のアイテムを返すだけです(したがって、 への呼び出しFirstは常に保証されます)。成功した)。

基本的に、グループ化中ではなく、グループ化の結果にセレクター適用しています。

于 2012-04-16T20:59:31.763 に答える
0

よりも大きいとbool実装するという事実を採用できます。IComparable<bool>truefalse

var distinctList = itemList.GroupBy(x => x.Id,  
    (key, group) => group.OrderByDescending(x => x.IsSelected).First()); 

ただし、これにはグループ全体を列挙して並べ替える必要があるため、このアプローチに固執すればパフォーマンスが向上します。

アイテムが選択されているグループの場合、このアプローチでは、最初に選択されたアイテムのポイントまでリストを 2 回繰り返す必要があります。この重複を次のように削除できます。

var distinctList = itemList.GroupBy(x => x.Id,  
    (key, group) => group.FirstOrDefault(x => x.Selected) ?? group.First()); 
于 2012-04-16T21:06:06.930 に答える