1

If I have a list inside a class inside of a list where the classes are defined like so:

class Class1
{
    public int Id { get; set; }

    public List<Class2> Class2s { get; set; }
}

class Class2
{
    public string Name { get; set; }

    public string Value { get; set; }
}

I can create a list of a class of type Result where Result is:

class Result
{
    public int Class1Id { get; set; }

    public string Name { get; set; }

    public string Value { get; set; }
}

Note that the Result class contains values from Class1 and Class2.

Like so:

var results = new List<Result>();
foreach (var class1 in class1s) //class1s is a List of Class1
{
    foreach (var class2 in class1.Class2s)
    {
        results.Add(new Result()
        {
            Class1Id = class1.Id,
            Name = class2.Name,
            Value = class2.Value,
        };
    }
}

How can I do this via a linq query?

I have tried the following:

IList<Result> list = class1s.Select(c => c.Class2s.Select(c2 => new Result()
{
    Class1Id = c.Id,
    Type = c2.Type,
    Name = c2.Name,
}).ToList()).ToList();

But this fails with the error:

Cannot implicitly convert type 'System.Collections.Generic.List<System.Collections.Generic.List<Results>' to 'System.Collections.Generic.IList<Results>'. An explicit conversion exists (are you missing a cast?)

NOTE:

The duplicates do not answer the question as they do not address the issue when the resultant list is a list of the inner classes AND using a property of the inner class.

TheLethalCoder
  • 6,668
  • 6
  • 34
  • 69
  • @CodeCaster and how am I supposed to do that with SelectMany when one of the properties is in the outer class not the list? – TheLethalCoder Sep 30 '16 at 13:06
  • I suggest you edit the title and question to explain that you want to include data from the parent objects. As it is, the immediate answer to "How to flatten a list of lists" is "Use SelectMany". The one important difference is lost in the code – Panagiotis Kanavos Sep 30 '16 at 13:15
  • 1
    You don't have a list of lists either, you have a list of parent and child objects. – Panagiotis Kanavos Sep 30 '16 at 13:17
  • @PanagiotisKanavos Is the edit any better? I'm having trouble coming up with a title so any help is appreciated – TheLethalCoder Sep 30 '16 at 13:19

2 Answers2

7

Retrieving data from a list of parents and children can be done easily in query format by using two from statements

var results = from parent in class1s
              from child in parent.Class2s 
              select new Result {
                    Class1Id = parent.Id,
                    Name = child.Name,
                    Value = child.Value,
              };
var list=results.ToList();

In the fluent format, you can use SelectMany

var list = class1s.SelectMany(parent => parent.Class2s,
                              (parent,child)=>
                                           new Result {
                                              Class1Id = parent.Id,
                                              Name = child.Name,
                                              Value = child.Value
                                          }
           ).ToList();

I prefer the first form for obvious reasons

Notice that I use the SelectMany overload that accepts a result selector. Without it I'd have to use a Select inside the first selector function, resulting in even more cumbersome code

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
2

You can do this in non-query format using the following:

results = class1s.SelectMany(c => c.Class2s.Select(c2 => new Result()
        {
            Class1Id = c.Id,
            Name = c2.Name,
            Value = c2.Value,
        })).ToList();

Note that it's very similar to your original attempt but using SelectMany on the class1s rather than Select.

petelids
  • 12,305
  • 3
  • 47
  • 57