首页 > 解决方案 > c# 按顺序对嵌套列表进行分组

问题描述

我在 c# 中生成如下的 yaml:

- type: DEFAULT
  primitives:
  - sequenceNo: 1
    from: Environment
    to: uC
    event: register
- type: DEFAULT
  primitives:
  - sequenceNo: 4
    from: uP
    event: start cells
- type: LOOP
  primitives:
  - sequenceNo: 5
    from: uC
    to: uP
    event: keepAlive Question
- type: LOOP
  primitives:
  - sequenceNo: 6
    from: uP
    to: uC
    event: keepAlive Response
- type: DEFAULT
  primitives:
  - sequenceNo: 10
    from: uC
    to: uP
    event: switch off uP

以下是我的课程:

public class Type
{
    public string type { get; set; }
    public List<Primitive> primitives { get; set; }
}

public class Primitive
{
    [YamlIgnore]
    public int sequenceNo { get; set; }
    [YamlIgnore]
    public int startX { get; set; }
    [YamlIgnore]
    public int startY { get; set; }
    public string from { get; set; }
    public string to { get; set; }
    [YamlMember(Alias = "event")]
    public string events { get; set; }
    public string expectedState { get; set; }
}

我想将列表分组如下:

- type: DEFAULT
  primitives:
    - from: environment
      to: uC
      event: register
    - from: uP
      event: start cells
- type: LOOP
  primitives:
    - from: uC
      to: uP
      event: keepAlive Question
    - from: uP
      to: uC
      event: keepAlive Response
- type: DEFAULT
  primitives:
    from: uC
    to: uP
    event: switch off uP

这意味着,我想根据类型按顺序对它们进行分组。如果我能找到相同的组,例如一个接一个的 DEFAULT,我必须将 2 个顺序 DEFAULT 的原语分组到一个 DEFAULT 中,依此类推。我怎样才能做到这一点。到目前为止,我已经尝试使用如下字典:

var res = types.GroupBy(r => r.type)
                  .ToDictionary(t => t.Key, t => t.Select(r => r.primitives).ToList());

但我没有按顺序获得列表。

标签: c#linqgrouping

解决方案


每当您有一系列相似的项目,并且您想要创建具有共同点的项目组时,请考虑使用GroupBy的重载之一。

您希望使这些组的Primitives属性具有相同的值Type。我的建议是使用具有参数 resultSelector 的 GroupBy 的重载。

(为了防止对类 Type 和属性 Type 的误解,我使用 originalType 来标识你原来的 Types 集合中的一个元素)

首先,我将创建original types具有相同属性类型值的组。然后,从这个 Group 中的元素序列(它们是原始类型)中,获取它们的基元,并将其展平(SelectMany)。从中选择所需的属性。

// make groups of Types that have same value of property Type:
IEnumerable<Type> originalTypes = ...
var result = originalTypes.GroupBy(originalType => originalType.Type,

// parameter resultSelector: from every Type, and all original types that have this
// value of property Type, make one new:
(type, originalTypesThatHaveThisValueForType) => new
{
    Type = type,

    // to get all primitives, use SelectMany to flatten the elements in this group
    Primitives = originalTypesThatHaveThisValueForType
        .SelectMany(originalType => originalType.Primitives,

        (originalType, primitive) => new
        {
            From = primitive.From,
            To = primitive.To,
            ...
        })
        .ToList(),
});

换句话说:从您的原始类型序列中,创建具有相同属性类型值的类型组。

从您创建的每个组中,创建一个具有两个属性的对象:TypePrimitives。属性 Type 的值很简单:这是组中所有原始类型的共同值。

为了创建 property Primitives,我们将组中的每个元素展平。请记住:该组是一组“带有原始类型的类型”(=原始类型)。我们使用 SelectMany 将其扁平化为 [原始类型,原始类型] 的组合。

因此,如果原始类型 A 具有基元 1、2、3;并且原始类型 B 具有原语 6、7,我们得到组合:

[A,原始 1] [A,原始 2] [A,原始 3] [B,原始 6] [B,原始 7]

我们将不再使用 A 和 B 中的任何内容,我们已经将它们的共同值用于属性类型。但我们对原语感兴趣:从组合中的每个原语中,我们制作一个对象:

// from every combination, make one new object:
(originalType, primitive) => new {...}

推荐阅读