【问题标题】:Convert flat object to hierarchy with c#使用 c# 将平面对象转换为层次结构
【发布时间】:2019-10-01 15:59:41
【问题描述】:

我见过类似的问题,但没有回答我的情况。所以……

给定类型:

public class Flat
{
    public string Group1 { get; set; }
    public string Group2 { get; set; }  
    public int Value { get; set; }
}

public class Group1 
{
    public Name { get; set; }
    public Group2[] Group2 { get; set; }
}

public class Group2
{
    public Name { get; set; }
    public int[] Values;
}

我想将 Flat 数组转换为上面指定的 Group1/Group2 层次结构。数组如下:

var flats = new []
    {
        new Flat { Group1 = "G1", Group2 = "G1.1", Value = 12 },
        new Flat { Group1 = "G1", Group2 = "G1.1", Value = 22 },
        new Flat { Group1 = "G1", Group2 = "G1.2", Value = 13 },
        new Flat { Group1 = "G2", Group2 = "G1.1", Value = 14 },
        new Flat { Group1 = "G2", Group2 = "G2.2", Value = 15 },
    };

所以输出将相当于:

var result = new []
{
    new Group1 
    { 
        Name = "G1"
        Group2 = [] 
        {
            new Group2 
            { 
                Name = "G1.1" 
                Values = [] { 12, 22 }
            },
            new Group2 
            { 
                Name = "G1.2" 
                Values = [] { 13 }
            },
        }
    },
    new Group1 
    { 
        Name = "G2"
        Group2 = [] 
        {
            new Group2 
            { 
                Name = "G2.1" 
                Values = [] { 14 }
            },
            new Group2 
            { 
                Name = "G2.2" 
                Values = [] { 15 }
            },
        }
    }
}

我尝试过使用GroupBy,但失败了:

var result = flats
        .GroupBy(f => f.Group1)
        .Select(f => f.GroupBy(x => x.Group2).Select(y => y.Select(x => x.Value)));

我一直在linqpad 中处理这个问题,但没有找到解决方案。我最初一直在尝试匿名类型,但添加了组类型。

linq 可以做到这一点吗?

【问题讨论】:

  • 我不清楚“输出将是”是什么意思。您是真的想要控制台输出,还是期待某种对象结构?如果是后者,您希望在哪里成为什么对象?您已经展示了“扁平”结构 - 如果您可以根据对象而不是“输出”来展示预期结果,这将使问题更容易回答。
  • 嘿乔恩,我已经在问题中指定了组层次结构。将重做。
  • 到目前为止你有什么尝试?
  • 我一直在尝试使用 GroupBy 解决,但没有成功。
  • 直接使用扩展方法会让事情变得更难。是的,你可以做一些你不能用 LINQ 语法做的事情,但是从“硬方式”开始是一种温和的自虐形式。从 LINQ 语法开始,然后仅在您确定需要的特定内容时进行更改(例如 Select 获取索引)。

标签: c# linq data-structures


【解决方案1】:

您可以执行以下 Linq 操作:

   Group1 [] res = flats.GroupBy( g1 => g1.Group1, 
      (key1,res1) => new Group1{ Group2 = 
         res1.GroupBy( g2 => g2.Group2, 
             (key2,res2) => new Group2{ Values = res2.Select( v => v.Value).ToArray(), 
             Name = key2}).ToArray(), Name = key1}).ToArray();

首先按 Group1 字符串分组,内部组创建一个 Group2 数组,该数组通过选择整数值并创建一个数组来初始化。

【讨论】:

    【解决方案2】:

    您只需要使用 LINQ 在两个级别上构建分组:

    var ans = flats.GroupBy(f => f.Group1)
                   .Select(fg => new Group1 {
                                    Name = fg.Key,
                                    Group2 = fg.GroupBy(f => f.Group2).Select(fg2 => new Group2 {
                                                                                Name = fg2.Key,
                                                                                Values = fg2.Select(f => f.Value).ToArray()
                                                                              })
                                                                       .ToArray()
                           })
                   .ToArray();
    

    注意:一般来说,最好使用ToList 而不是ToArray,除非您对Array 类型有特殊需求(通常与其他代码的互操作性)。

    【讨论】:

      【解决方案3】:

      这应该可以解决问题。您想对一个组的结果进行分组。所以分组 2 次。

      var result = flats.GroupBy(x => x.Group1).Select(group1 => new Group1()
      {
          Name = group1.Key,
          Group2 = group1.GroupBy(x => x.Group2).Select(group2 => new Group2()
          {
              Name = group2.Key,
              Values = group2.Select(x => x.Value).ToArray()
          }).ToArray()
      });
      

      【讨论】:

      • 我想你的意思是两次分组。
      猜你喜欢
      • 2016-06-25
      • 2018-02-23
      • 1970-01-01
      • 2021-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-06
      • 1970-01-01
      相关资源
      最近更新 更多