Reputation: 3
I have a List<List<string>>
in C# as below (output from Immediate window):-
macthedList Count = 2
macthedList[0]
[0]: "Rob"
[1]: "23"
[2]: "Math"
[3]: "98"
macthedList[1]
[0]: "Jim"
[1]: "25"
[2]: "Science|Math|LA"
[3]: "92|99|89"
I would like to flatten the above to get a list of 4 lists like below:-
macthedList Count = 4
macthedList[0]
[0]: "Rob"
[1]: "23"
[2]: "Math"
[3]: "98"
macthedList[1]
[0]: "Jim"
[1]: "25"
[2]: "Science"
[3]: "92"
macthedList[2]
[0]: "Jim"
[1]: "25"
[2]: "Math"
[3]: "99"
macthedList[3]
[0]: "Jim"
[1]: "25"
[2]: "LA"
[3]: "89"
Can you please show me how do I do it using LINQ
? I guess we use 'SelectMany' but not entirely sure how.
Upvotes: 0
Views: 293
Reputation: 32296
Here's the pure Linq code for that
var result = source.SelectMany(
x => x[2].Split('|')
.Zip(x[3].Split('|'), (c, s) => new { Course = c, Score = s })
.Select(cs => new List<string> { x[0], x[1], cs.Course, cs.Score}))
.ToList();
Note that if the number of pipes in the 3rd and 4th strings of the sub-lists do not match up this would result in the shorter of the two. It also will throw if any of the sub-lists do not have at least 4 items.
Upvotes: 0
Reputation: 4219
This solution solves the specific case you've outlined (disregarding any exceptions to the logic) using SelectMany()
, although it's not necessarily pretty:
var matchedList = new List<List<string>> {
new List<string> { "Rob", "23", "Math", "98" },
new List<string> { "Jim", "25", "Science|Math|LA", "92|99|89" }
};
List<List<string>> flattened = matchedList.SelectMany(s =>
{
var courses = s[2].Split('|');
var grades = s[3].Split('|');
return courses.Select((c, index) => new List<string> { s[0], s[1], c, grades[index] });
}).ToList();
As others have mentioned, if you want this code to be maintainable, readable, testable, and generally decent you should consider translating these lists into well defined objects that encapsulate this logic.
Upvotes: 1
Reputation: 14251
var source = new List<List<string>> {
new List<string> { "Rob", "23", "Math", "98" },
new List<string> { "Jim", "25", "Science|Math|LA", "92|99|89" }
};
var result = new List<List<string>>();
foreach (var list in source)
{
var name = list[0];
var age = list[1];
var courses = list[2].Split('|');
var scores = list[3].Split('|');
for (int i = 0; i < courses.Length; i++)
{
var temp = new List<string>();
temp.Add(name);
temp.Add(age);
temp.Add(courses[i]);
temp.Add(scores[i]);
result.Add(temp);
}
}
foreach (var list in result)
{
Console.WriteLine(string.Join(", ", list));
}
Upvotes: 0