Bob
Bob

Reputation: 191

How to remove all items from nested list while iterating in C#

I have a nested list that contains

public class Person
{
    public Person(string name)
    {
        this.Name = name;
    }

    public string Name { get; set; }

    public List<Person> Childs { get; set; }
}

The list can be used like:

    var Persons = new List<Person>();
    Persons.Add(new Person("Eric"));
    Persons[0].Childs = new List<Person>();
    Persons[0].Childs.Add(new Person("Tom"));
    Persons[0].Childs.Add(new Person("John"));
    Persons[0].Childs[0].Childs = new List<Person>();
    Persons[0].Childs[0].Childs.Add(new Person("Bill"));
    Persons.Add(new Person("John");

How can I iterate over the list Persons and remove all items with the name "John"? If the name is John the node with the name John and all underlaying subitems should be removed.

Upvotes: 2

Views: 1050

Answers (4)

GregorMohorko
GregorMohorko

Reputation: 2857

Here is a recursive method that removes all persons with the specified name. You can call it like RemoveAllWithName(Persons, "John");.

private void RemoveAllWithName(List<Person> people, string name)
{
    for(int i = people.Count - 1; i >= 0; --i) {
        Person person = people[i];
        if(person.Name == name) {
            people.RemoveAt(i);
        } else if(person.Childs != null) {
            RemoveAllWithName(person.Childs, name);
        }
    }
}

Upvotes: 0

Enigmativity
Enigmativity

Reputation: 117029

You're better off not removing the elements from the existing structure but instead to return a new structure without the "John"'s.

Here's how:

List<Person> Except(List<Person> people, string name) =>
    people
        .Where(p => p.Name != name)
        .Select(p => new Person(p.Name)
        {
            Childs = Except(p.Childs ?? new List<Person>(), name) // Case typo in method name
        })
        .ToList();

If you start with your original data:

var Persons = new List<Person>()
{
    new Person("Eric")
    {
        Childs = new List<Person>()
        {
            new Person("Tom"),
            new Person("John")
            {
                Childs = new List<Person>()
                {
                    new Person("Bill")
                }
            }
        }
    },
    new Person("John")
};

You can now run this:

List<Person> PersonsNotJohn = Except(Persons, "John");

That gives:

PersonsNotJohn

Upvotes: 2

Enver Krynitski
Enver Krynitski

Reputation: 87

static void Main(string[] args)
    {
        var Persons = new List<Person>();
        Persons.Add(new Person("Eric"));
        Persons[0].Childs = new List<Person>();
        Persons[0].Childs.Add(new Person("Tom"));
        Persons[0].Childs.Add(new Person("John"));
        Persons[0].Childs[0].Childs = new List<Person>();
        Persons[0].Childs[0].Childs.Add(new Person("Bill"));
        Persons.Add(new Person("John"));
        RemoveAllWithName("John", Persons);
        Persons.ForEach(x=>Print(x));
    }
    private static void RemoveAllWithName(string name, List<Person> persons)
    {
        if (persons != null && persons.Any())
        {
            persons.RemoveAll(x => x.Name == name);
        }
        if (persons != null && persons.Any())
        {
            persons.ForEach(x => RemoveAllWithName(name, x.Childs));
        }
    }
    private static void Print(Person person)
    {
        if (person != null)
        {
            Console.WriteLine(person.Name);
            person.Childs?.ForEach(Print);
        }
    }

Upvotes: 0

Gagan Deep
Gagan Deep

Reputation: 1509

Here you go.

Add Namespace

using System.Linq;

Use the below one liner

Persons.RemoveAll(x => x.Name == "John");

Upvotes: 0

Related Questions