Home > front end >  In .NET Want to select all IDs from a list of objects by flattening a nested object?
In .NET Want to select all IDs from a list of objects by flattening a nested object?

Time:11-11

Model for my Application

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

Nested List of Persons

List<Person> personList = new List<Person>();

Person parent = new Person() { ID = 1, Name = "A" };
parent.Children.Add(new Person() { ID = 2, Name = "B" });
parent.Children.Add(new Person() { ID = 3, Name = "C" });
personList.Add(parent);

parent = new Person() { ID = 2, Name = "D" };
parent.Children.Add(new Person() { ID = 4, Name = "E" });
parent.Children.Add(new Person()
{
    ID = 5,
    Name = "F",
    Children = new List<Person>(){
    new Person() { ID =6, Name = "G" },
    new Person() { ID = 7, Name = "H" }}
});
personList.Add(parent);
personList.SelectMany(x => x.Children);

List of Ids in one list from all nested children using LINQ

CodePudding user response:

Please refer to this answer

Solution:

Create an extension method

public static class IEnumerableExtensions
{
    public static IEnumerable<T> SelectManyRecursive<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> selector)
    {
        if (source == null) throw new ArgumentNullException(nameof(source));
        if (selector == null) throw new ArgumentNullException(paramName: nameof(selector));

        return !source.Any() ? source :
            source.Concat(
                source
                .SelectMany(i => selector(i).EmptyIfNull())
                .SelectManyRecursive(selector)
            );
    }

    public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> source)
    {
        return source ?? Enumerable.Empty<T>();
    }
}
// ....
personList.Add(parent);

var flattenedLitOfPersons = personList.SelectManyRecursive(q => q.Children);

var ids = flattenedLitOfPersons.Select(q => q.ID);

CodePudding user response:

You could use this recursive extension method:

public static IEnumerable<T> Flatten<T>(this IEnumerable<T> seq, Func<T, IEnumerable<T>> getChildren)
{
    foreach (var item in seq)
    {
        yield return item;

        foreach (var subItem in getChildren(item).Flatten<T>(getChildren))
        {
            yield return subItem;
        }
    }
}

With your sample:

List<int> allPersonIdList = personList
    .Flatten<Person>(p => p.Children)
    .Select(p => p.ID)
    .ToList();

If you want a unique list of ID's put a Distinct before the ToList.

  • Related