14

How to convert the nested hierarchical object to flatten objects by using LINQ? I know that we can easily use foreach loop to achieve that. But I'm wondering if there is a way to write it in LINQ.

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

Data :

ID   : 1

Name : Jack

Children

2 | Rose 

3 | Paul

I like to convert this data into flatten format like below.

1 | Jack 

2 | Rose 

3 | Paul

How can we do it with Linq?

2 Answers 2

19

If you want it to flatten an arbitrarily deep tree of people, I suggest the following:

public IEnumerable<Person> GetFamily(Person parent)
{
    yield return parent;
    foreach (Person child in parent.Children) // check null if you must
        foreach (Person relative in GetFamily(child))
            yield return relative;
}

There isn't really any good way to shorten this with LINQ, because anonymous lambdas can't call themselves recursively without implementing Y. You could "reduce" the above method to

return parent.Children.SelectMany(p => GetFamily(p))
                      .Concat(new Person[] { parent });

or alternatively

yield return parent;
    foreach (Person relative in parent.Children.SelectMany(GetFamily))
        yield return relative;

but that seems sort of unnecessary to me.

Sign up to request clarification or add additional context in comments.

7 Comments

Of course lambdas can call themselves. Here's Fibonacci using a recursive lambda: Func<int, int> fib = null; fib = i => i <= 1 ? i : fib(i-1) + fib(i-2);
I said "anonymous lambdas can't call themselves", which is why he can't write a single expression that returns the value he wants -- he needs to declare a named function to recurse with.
So by putting something anonymous in a variable it is no longer anonymous? E.g. var a = new { X = 5 };? I'd still call what a references an anonymous type. Microsoft unconditionally says that "A lambda expression is an anonymous function" and look at the second example of Anonymous Methods. Almost everything anonymous has to be put in some kind of named variable or parameter; otherwise they're not usable by code. That doesn't mean they're not anonymous.
I'm going to keep using the word "anonymous" to mean "not identified by name." In your example, the type is anonymous, but the object is not anonymous.
You're just using words in a way that I don't think is common parlance. I appeal to the Wikipedia page: en.wikipedia.org/wiki/Anonymous_function "In programming language theory, an anonymous function (also function constant, function literal, or lambda function) is a function (or a subroutine) defined, and possibly called, without being bound to an identifier." Saying "objects do not have names" is not how I care to use the word "name", so we will remain in disagreement about that.
|
8

This is a nice, generic and reusable extension method:

static public IEnumerable<T> Descendants<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> descendBy)
{
    if (!source.IsNullOrEmpty())
    {
        foreach (T value in source)
        {
            yield return value;

            if (!descendBy(value).IsNullOrEmpty())
            {
                foreach (T child in descendBy(value).Descendants<T>(descendBy))
                {
                    yield return child;
                }
            }
        }
    }
}

In the case above, use like this:

var allChildren = parent.Children.Descendants(p => p.Children);

One minor nit is that it doesn't include the original parent in the list, you'll need to do that.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.