Reputation: 5858
I've seen similar questions but not something which answers my scenario. So...
Given the types:
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;
}
I want to convert the Flat array to the Group1
/Group2
hierarchy specified above. The array is as follows:
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 },
};
So the output will be equivalent to:
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 }
},
}
}
}
I have tried and failed using GroupBy
:
var result = flats
.GroupBy(f => f.Group1)
.Select(f => f.GroupBy(x => x.Group2).Select(y => y.Select(x => x.Value)));
I've been fiddling with this in linqpad
but not found a solution. I've been trying anonymous types initially but added the group types.
Is this possible with linq
?
Upvotes: 0
Views: 608
Reputation: 2026
This should do the trick. You want to group the results of a group. So group 2 times.
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()
});
Upvotes: 1
Reputation: 26936
You just need to use LINQ to build the groupings at two levels:
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();
NOTE: In general, it is better to prefer ToList
instead of ToArray
unless you have a specific need for the Array
type (normally interoperability with other code).
Upvotes: 1
Reputation: 6783
You can perform the following Linq operation :
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();
First grouping by the Group1 string, the inner group creates an array of Group2 which is initialised by selecting the integer values & creating an array.
Upvotes: 1