使用if else条件对Linq GroupBy对象进行分组

3

我很新于c#的linq,遇到了一些困难。

我有一个列表,并且想从中获取特定的信息,就像以下示例:

假设我有以下kidsEat对象列表:

{NAME=joseph, FOOD=banana, EATEN=true}
 
{NAME=joseph, FOOD=apple, EATEN=false}

{NAME=billy, FOOD=banana, EATEN=false}

{NAME=billy, FOOD=apple, EATEN=false}

我想知道这个列表中的每一个男孩是否吃过东西。

如果他吃了东西,返回说明他吃了什么的对象。

如果他没有吃,返回一件他没有吃过的随机物品。

因此,此示例应返回以下2个对象的列表:

{NAME=joseph, FOOD=banana, EATEN=true}

{NAME=billy, FOOD=banana, EATEN=false}     //banana could be switched to apple, it doesn't matter

好的,我想到了这样一个东西:

KidsList.GroupBy(kid=>kid.NAME).Where().Select(kid=>kid.First())

但我不知道在where子句里应该放什么,因为它会遍历所有行,然后找到是否有一个结果为true,如果是,则放置“true”,否则放置false。感觉需要在LINQ查询中加入一些if else语句。

需要帮助吗?


不要使用全大写的属性名称;请使用帕斯卡命名法,例如 NameFoodEatenSomethingElse 等。 - atiyar
4个回答

6
选择第一条“已吃掉”的记录,如果没有“已吃掉”的记录,则选择第一条“未吃掉”的记录。
KidsList.GroupBy(k => k.NAME)
  .Select(g => g.FirstOrDefault(k => k.EATEN) ?? g.First())

解释:如果没有记录与k => k.EATEN谓词匹配,则 FirstOrDefault 将返回默认值,即null。在这种情况下,null 合并运算符 ?? 将评估右操作数并返回First记录(显然将是'not eaten')。


3
您可以按照EATEN的顺序对组元素进行排序,然后选择第一个元素:
var ans = src.GroupBy(e => e.NAME)
             .Select(eg => eg.OrderByDescending(e => e.EATEN).First());

2

需求:

从这个列表中,我想知道每个男孩是否吃过东西。 如果他吃了东西,就会获取标记为他吃的对象。 如果他没有吃东西,就会取一个他没吃过的随机对象。

如果其中一个男孩吃了多种物品怎么办?什么是“获取标记为他吃的对象”?
所以我们可以改成:“获取他吃的任何对象”。
如果你确定没有人吃了多种物品,那么没有区别。

对于这个问题,不需要使用Where

首先,您需要知道每个孩子吃过和未吃过的物品。按照已吃的值进行降序排列:先是已吃的食物(=true),然后是未吃的食物(=false)。从这个物品序列中取第一项。

如果孩子至少吃了一样东西,那么第一项将是一个已吃的物品。如果他没有吃任何东西(即如果所有已吃的出现都是false),那么第一项将是一个未吃的物品。

我们将使用Enumerable.GroupBy的重载,该重载具有参数resultSelector。在resultSelector中,我们将按照上述方式对Eaten的值进行OrderByDescending排序。然后,我们将选择第一个Food。

IEnumerable<KidsEat> kidsEats = ...
var result = kidsEats.GroupBy(kid => kid.Name,

    // parameter resultSelector: for every kid's Name, and all kidsEats with this Name
    // make one new object:
    (name, kidsEatsWithThisName) => new
    {
        Name = name,
        Food = kidsEatsWithThisName
               .OrderByDescending(kidsEat => kidsEat.Eaten)
               .Select(kidsEat => kidsEat.Food)
               .FirstOrDefault(),
    });

简单来说:从kidsEats序列中,将具有相同名称的kidsEats分组。从每个组中制作一个新对象,其属性NameFood如下:

  • Name属性的值是该组的键,即该组中所有kidsEats的共同名称。
  • 为了计算Food属性的值,按照Eaten属性的降序值对该组中的所有KidsEats进行排序:首先是真实的值,然后是假值。
  • 从这个已排序的KidsEats序列中取出Food属性的值。结果:一系列Foods,首先是由这个名称的孩子吃掉的Foods,然后是这个孩子没有吃掉的Foods。
  • 从这个Foods序列中取出第一项。如果这个孩子什么都没吃,那么第一项就是未吃掉的Food。如果他吃了任何东西,那么这个第一项就是吃掉的Food。

简单得不能再简单了!(一旦你知道怎么做)


1

一种方法是使用Aggregate函数。

list.GroupBy(k => k.NAME)
  .Select(g => g.Aggregate ((x, y) => x.EATEN && !y.EATEN ? x : y))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接