Преобразовать плоский объект в иерархию с помощью c # - PullRequest
0 голосов
/ 01 октября 2019

Я видел похожие вопросы, но не то, что отвечает моему сценарию. Итак ...

Учитывая типы:

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?

Ответы [ 3 ]

1 голос
/ 01 октября 2019

Это должно сработать. Вы хотите сгруппировать результаты группы. Итак, группа 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()
});
1 голос
/ 01 октября 2019

Вам просто нужно использовать 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 (обычно совместимость с другим кодом).

1 голос
/ 01 октября 2019

Вы можете выполнить следующую операцию 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, который инициализируется путем выбора целочисленных значений и создания массива.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...