Blah
Blah

Reputation: 63

Flattening a list of lists, using LINQ, to get a list of parent/child

I am trying to flatten a parent/child list, of the same <Person> type. The difficulty here, is that I would like to merge both the parents and children into a flat <Person> list.

Closest I got was:

class Person
{
    public string Name { get; set; }
    public List<Person> Children { get; set; }
}

List<Person> parents = new List<Person>() {
    new Person() {
        Name = "parentA",
        Children = new List<Person>() {
            new Person() { Name = "childB" },
            new Person() { Name = "childC" }
        }
    },
    new Person() {
        Name = "parentD",
        Children = new List<Person>() {
            new Person() { Name = "childE" },
            new Person() { Name = "childF" }
        }
    }
};

var result = parents.SelectMany(parent => parent.Children
    .Select(child => parent.Name + ", " + child.Name));

Which gives me the result:

parentA, childB
parentA, childC
parentD, childE
parentD, childF

What I'm looking for is to get a <Person> list such as:

parentA
childB
childC
parentD
childE
childF

Keeping the order, or the performance is not important. But I would like, if possible, to stick to pure LINQ and LINQ methods.

Thanks,

Upvotes: 0

Views: 2742

Answers (4)

Blah
Blah

Reputation: 63

Thanks to the comments on my initial post, I was able to get what I was looking for.

The solution only works on one level, which is what I needed. It could be made recursive to go deeper though:

var result = parents.SelectMany(person => person.Children
        .Prepend(person))
    .Select(p => p.Name);

Gave me the expected result:

parentA 
childB 
childC 
parentD 
childE 
childF 

Which then allowed me to use all the objects in the flattened lists, including the parent objects.

Upvotes: 3

jdweng
jdweng

Reputation: 34421

Try following class :

    class Person
    {
        public static DataTable dt { get;set;}

        public string Name { get; set; }
        public List<Person> Children { get; set; }

        public void GetTree(Person root)
        {
            DataTable dt = new DataTable();
            dt.Columns.Add("Parent Name", typeof(string));
            dt.Columns.Add("Child Name", typeof(string));
            GetTreeRecursive(root, "");

        }
        public void GetTreeRecursive(Person person, string parentName)
        {
            foreach(Person child in person.Children)
            {
                dt.Rows.Add(parentName, child.Name);
                if (child.Children != null)
                {
                    GetTreeRecursive(child, child.Name);
                }
            }
        }
    }

Upvotes: 0

Dmitrii Bychenko
Dmitrii Bychenko

Reputation: 186668

I suggest Concat in combination with SelectMany if you want just one level deep:

 var parents = ...

 var result = parents
   .SelectMany(person => new Person[] {person}.Concat(person.Children))
   .Select(person => person.Name); // if we want just names

 // Let's have a look
 Console.WriteLine(string.Join(Environment.NewLine, result));

Upvotes: 1

shahkalpesh
shahkalpesh

Reputation: 33476

var persons = new List<Person>();
parents.ForEach(p => {
        persons.Add(p); 
        persons.AddRange(p.Children);
    }
);


foreach(var person in persons)
        Console.WriteLine(person.Name);
    }

I understand that this isnt a single line but this I suppose is what you are looking for.

Upvotes: 0

Related Questions