【问题标题】:LINQ lambda expression, finding a child object where property is == XLINQ lambda 表达式,查找属性为 == X 的子对象
【发布时间】:2014-05-21 21:30:59
【问题描述】:

需要有关 C# 中 LINQ lambda 表达式的帮助。

那么让我解释一下我的对象的结构。

RootObject 是一个集合(具有多个属性的自定义类),它具有许多属性,其中一个是List<Item> 项目。 项目包含一个List<Round> 回合。 Round 包含一个EntryRID(此ID 是唯一的)和name

string = IDToFind = "111"; //The ID i want a Round object for 

因此,我需要从我的“项目”列表中找到与给定 ID (IDToFind) 匹配的回合 ID。 AKA 我需要在“items”中搜索每个单项以查找 ID 与 IDToFind 匹配的 Round 对象。

我已经厌倦了这个表达:

Round playerRound = RootObject.Select(i => i.Items.Select(x => x.Rounds.Where(y => y.EntryRID == Int32.Parse(IDToFind))));

但它不返回任何类型的对象,它返回:

System.Linq.Enumerable+WhereSelectListIterator`2[Leaderboards,System.Collections.Generic.IEnumerable`1[System.Collections.Generic.IEnumerable`1[Round]]]

【问题讨论】:

  • 嗯,是的,您已经创建了一个查询 - 您需要遍历结果...或使用 First()Single() 或其他任何方法来获得单个结果。您可能还想使用SelectMany 来展平结果...这无济于事,您要查找的结果类型并不明显。
  • 好吧,我确实用文字解释了它:),但现在我添加了我正在寻找的对象(请参阅更新后的帖子,表达式)
  • 那么如果有多个匹配项你想做什么?
  • 不可能因为回合的 ID 是 100% 唯一的。
  • 你可以看到FirstSingle

标签: c# linq lambda


【解决方案1】:

听起来你想要这样的东西:

// Parse the target ID *once* rather than all the time...
var targetId = int.Parse(IDToFind);
var playerRound = RootObject.SelectMany(i => i.Items)
                            .SelectMany(x => x.Rounds)
                            .Where(round => round.EntryRID == targetId)
                            .First();

这将返回 first 匹配Round,或者如果没有异常则抛出异常。您可以使用FirstOrDefault,如果没有匹配的对象,它将返回null,或者可能使用Single(),这将确保完全有一个结果。

作为查询表达式,你可以将上面写成:

var targetId = int.Parse(IDToFind);
var playerRound = (from foo in RootObject // You haven't told us this type
                   from item in foo.Items
                   from round in item.Rounds
                   where round.EntryRID == targetId
                   select round).First();

【讨论】:

  • 感谢您的建议,我忘了说 RootObject 也是一个具有许多属性的集合,其中一个是 List 项。如果您更新答案,很乐意再试一次。抱歉弄错了。
  • @user2408952:我的回答已经解决了这个问题——但你的描述不太正确;该集合没有Items 属性,它是具有该属性的集合的每个元素。这种事情正是为什么最好使用代码来演示问题而不仅仅是描述......
  • 是的,如果不是因为我的 RootObject 的属性是由 300 行代码构建的,我会发布代码。所以我假设没有人会费心阅读所有 300 行,因此我试图简化它(这似乎我没能做到)。
  • @user2408952:简化是件好事——但您仍然可以在代码中做到这一点。能够创建一个简短但完整的示例来演示问题是一项重要技能:)
【解决方案2】:

您的查询为每个RootObject 元素返回IEnumerables 中的IEnumerable。这是因为您的查询会为 RootObject 的每个项目生成一个 IEnumerable,并将结果也生成一个 IEnumerable

如果您想将结果扁平化为单个列表,请使用SelectMany,如下所示:

var matchingItems = RootObject.SelectMany(i => i.Items.SelectMany(x => x.Rounds.Where(y => y.EntryRID == Int32.Parse(IDToFind))));

上面生成了一个可以迭代的集合:

foreach (var item in matchingItems) {
    Console.WriteLine(item.ToString();
}

【讨论】:

  • 感谢您的建议,我忘了说 RootObject 也是一个具有许多属性的集合,其中一个是 List 项。如果您更新答案,很乐意再试一次。对不起这个错误。
  • @user2408952 我假设RootObject 是一个对象的集合——这就是为什么你可以在它上面做一个SelectMany。我错过了Rounds 也需要展平的事实。
【解决方案3】:

你得到的结果是一个迭代器,也就是说,如果你在 for 循环中使用它,你可以迭代单个元素,比如:

var element = RootObject.Select(i => i.Items.Select(x => x.Rounds.Where(y => y.EntryRID == Int32.Parse(IDToFind))));
for (var element in elements)
{ // do something with the element...}

如果您想立即查看整个列表,您还可以使用ToList() 方法为您获取所有元素并将它们放入List

var list = element.ToList();

【讨论】:

  • 感谢您的建议,我忘了说 RootObject 也是一个具有许多属性的集合,其中一个是 List 项。如果您更新答案,很乐意再试一次。很抱歉这个错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-09
  • 1970-01-01
  • 1970-01-01
  • 2011-11-23
  • 2017-08-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多