【问题标题】:c# IEnumerable<Object> LINQ GroupBy - Merge 2 Groupsc# IEnumerable<Object> LINQ GroupBy - 合并 2 个组
【发布时间】:2017-11-18 08:17:12
【问题描述】:

我正在研究一些 LINQ GroupBy 逻辑,但我想不出如何优雅高效地让它工作。

基本上,我有一个 IEnumerable&lt;Thing&gt; 对象(顺序正确!),其中每个 Thing 对象都有一个 RootId 属性。我想将这些对象按我正在工作的 RootId 分组:

IEnumerable<Thing> things; // Already has value assigned
var groups =
    (from thing in things
     group thing by thing.RootId into thingGroup
     select thingGroup.ToArray())
    .ToList();

groups 的类型是 List&lt;Thing[]&gt;

现在问题来了!

上面的示例返回列表中的 5 个项目。但是,我如何将 2 个数组合并为 1 个,留下 4 个项目(再次,当然保持顺序)??

原因是因为其中 2 个项目具有不同的 RootId,但我希望它们被视为相同,即组合在一起。

我打算在 LINQ 语句之后连接和操作数组,但实际上它需要作为 group by/LINQ 的一部分来完成 - 有什么想法吗?

如果需要更多示例或信息,请告诉我。

谢谢!

合并标准将是一个手动过程,因此我正在考虑将其传递给 groupby 方法,如下所示:

var rootIdsToMerge = new List<Tuple<ID, ID>>
{
    new Tuple<ID, ID>(rootIdOne, rootIdTwo),
    new Tuple<ID, ID>(rootIdThree, rootIdFour)
};

因此,RootId 为 rootIdOne 的任何组项都将与 RootId 为 rootIdTwo 的组项合并,依此类推。

【问题讨论】:

  • 那么对待 2 个 RootId 相同的标准是什么?例如硬编码值、其他属性还是?
  • 这将是一个手动过程,所以我正在考虑将它传递给这样的方法:var rootIdsToMerge = new List&lt;Tuple&lt;ID, ID&gt;&gt; { new Tuple&lt;ID, ID&gt;(rootIdOne, rootIdTwo), new Tuple&lt;ID, ID&gt;(rootIdThree, rootIdFour) };
  • 像什么?如果没有更具体的例子,我看不出我们如何回答。所以我们有IEnumerable&lt;Thing&gt;,还有什么?
  • 对不起,Ivan,我正在尽力提供帮助。我的新“rootIdsToMerge”代码有帮助吗?但是,是的,这两个对象就是我们所拥有的 - 我希望有一些很棒的 LINQ 查询来实现我所需要的:)

标签: c# arrays linq merge


【解决方案1】:

由于您没有使用分组Key,因此您可以将映射中的Item2 关联到Item1 作为RootId 键来分组:

var groups =
    (from thing in things
     group thing by rootIdsToMerge.FirstOrDefault(e => e.Item2 == thing.RootId)?.Item1 ?? thing.RootId
     into thingGroup
     select thingGroup.ToArray())
    .ToList();

或在 C#6 之前(无 .? 运算符):

var groups =
    (from thing in things
     let mergeWith = rootIdsToMerge.FirstOrDefault(e => e.Item2 == thing.RootId)
     group thing by mergeWith != null ? mergeWith.Item1 : thing.RootId
     into thingGroup
     select thingGroup.ToArray())
    .ToList();

更新:如果您只想合并RootIds 的列表,那么您可以使用ContainsFirst 的组合:

List<ID> rootIdsToMerge = ...;
var groups =
    (from thing in things
     group thing by rootIdsToMerge.Contains(thing.RootId) ? rootIdsToMerge.First() : thing.RootId
     into thingGroup
     select thingGroup.ToArray())
    .ToList();

带有

的变体
List<List<ID>> rootIdsToMerge = ...;

类似于带有元组的初始变体:

var groups =
    (from thing in things
     group thing by rootIdsToMerge.FirstOrDefault(ids => ids.Contains(thing.RootId))?.First() ?? thing.RootId
     into thingGroup
     select thingGroup.ToArray())
    .ToList();

var groups =
    (from thing in things
     let mergeList = rootIdsToMerge.FirstOrDefault(ids => ids.Contains(thing.RootId))
     group thing by mergeList != null ? mergeList.First() : thing.RootId
     into thingGroup
     select thingGroup.ToArray())
    .ToList();

【讨论】:

  • 谢谢伊万,这太棒了。我现在要考试了! :) 想一想,我猜 rootIdsToMerge 应该是 List 类型,这样可以合并 2 个以上的组。这是可行的吗?很抱歉添加更多工作!
  • 您是指List&lt;List&lt;ID&gt;&gt; 还是只是List&lt;ID&gt;
  • 取决于您是否想要一组以上的合并 ID - 他们编写查询的方式,您可以重复 Item1 并使用不同的 Item2s 来创建更大的组,还可以创建多个团体。否则你会想用List&lt;List&lt;ID&gt;&gt; 替换并且查询需要改变。
  • @IvanStoev 你的传奇! :) 非常感谢。如果不是太麻烦(对不起,呵呵),但我认为你是对的, List> 更有意义;)请最后一次更新? :)
  • 当然,这只是元组版本的变体。干杯。
猜你喜欢
  • 1970-01-01
  • 2020-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多