Rajat Suneja
Rajat Suneja

Reputation: 552

Filtering Out Object from Composite List C#

I have a composite list as follows-

List<RestApiD3Output> result = new List<RestApiD3Output>();

with the following model -

public class RestApiD3Output
{
    public string name { get; set; }
    public int? size { get; set; }
    public IList<RestApiD3Output> children { get; set; }
}

Now, I want to filter out all objects and its children where the name = test. So if a parent node's name = test and the children name is not = test I Still need the parent node.

So, If I have a data such as -

{
    "name": "Ford",
    "children": [
        {
          "name": "Figo",
          "children": [
                { "name": "Test", "size": 3938 },
                { "name": "Test1", "size": 3938 },
                {
                    "name": "Test2",
                    "children": [
                        { "name": "Test-1-1", "size": 3938 },
                        { "name": "Test-1-2", "size": 3938 }
                    ]
                }
            ]
        },
        {
            "name": "Test",
            "children": [
                { "name": "Test1", "size": 3938 },
                { "name": "Test2", "size": 3938 },
                { "name": "Test3", "size": 3938 }
            ]
        }
    ]
}

The desired output would be -

{
    "name": "Ford",
    "children": [
        {
            "name": "Figo",
            "children": [
                { "name": "Test", "size": 3938 }
            ]
        },
        {
            "name": "Test",
            "children": [
                { "name": "Test1", "size": 3938 },
                { "name": "Test2", "size": 3938 },
                { "name": "Test3", "size": 3938 }
            ]
        }
    ]
}

EDIT -

Clarifications to some questions.

Since the parent's name is Test, I would like to have the entire node, with all its children. And hence the presence of Test1 and Test2.

And if the parent node's name is not test but has a child with the name Test, then I would like to have the node with only the child element with the name Test.

EDIT 2

Scenarios -

  1. If a parent item is named "Test", keep it and all its children.
  2. If a parent item is not named "Test" but has any children named "Test", just keep the child with name "Test" for that item and eliminate rest children
  3. Otherwise delete the item.

Upvotes: 0

Views: 289

Answers (2)

Olivier Jacot-Descombes
Olivier Jacot-Descombes

Reputation: 112762

If you were using the same class at all levels, you could use a recursive approach. Assuming the class

public class Item
{
    public string name { get; set; }
    public int size { get; set; }
    public IList<Item> children { get; set; }
}

We can do

private bool KeepIt(Item item)
{
    return item.name.StartsWith("Test");
}

// This first solution removes all the nodes not having a name starting with "Test" and not
// having any children fulfilling the same condition. But, apparently this was not what the
/// OP wanted. Please, see my update.
public void PruneTree(IList<Item> items)
{
    for (int i = items.Count-1; i >= 0; i--) {
        PruneTree(items[i].children);
        if (items[i].children.Count == 0 && !KeepIt(items[i])) {
            items.RemoveAt(i);
        }
    }
}

call it with

PruneTree(result);

UPDATE

After your clarifications here is another solution fulfilling the following rules:

  1. If an item is named "Test", keep it and all its children.
  2. If an item has any children named "Test", keep it.
  3. Otherwise delete the item.
public void PruneTree(IList<Item> items)
{
    for (int i = items.Count - 1; i >= 0; i--) {
        Item item = items[i];
        if (item.name != "Test") {
            PruneTree(item.children);
            if (item.children.Count == 0) {
                items.RemoveAt(i);
            }
        }
    }
}

Test output before and after a call to PruneTree: enter image description here

This is my whole test class:

public static class FilteringOutObjectFromCompositeList
{
    public class Item
    {
        public Item()
        {
            children = new List<Item>();
        }

        public string name { get; set; }
        public int size { get; set; }
        public IList<Item> children { get; set; }
    }

    private static void PruneTree(IList<Item> items)
    {
        for (int i = items.Count - 1; i >= 0; i--) {
            Item item = items[i];
            if (item.name != "Test") {
                PruneTree(item.children);
                if (item.children.Count == 0) {
                    items.RemoveAt(i);
                }
            }
        }
    }

    public static void Test()
    {
        var root = new Item {
            name = "Ford",
            children = new List<Item> {
                 new Item {
                    name = "Figo",
                    children = new List<Item> {
                        new Item { name= "Test", size= 3938 },
                        new Item { name= "Test1", size= 3938 },
                        new Item {
                            name= "Test2",
                            children = new List<Item> {
                                new Item { name= "Test-1-1", size= 3938 },
                                new Item { name= "Test-1-2", size= 3938 }
                            }
                        }
                    }
                },
                new Item {
                    name= "Test",
                    children=new List<Item> {
                        new Item { name= "Test1", size= 3938 },
                        new Item { name= "Test2", size= 3938 },
                        new Item { name= "Test3", size= 3938 }
                    }
                }
            }
        };
        PrintTree(root, 0);
        PruneTree(root.children);
        Console.WriteLine("----------------------");
        PrintTree(root, 0);
        Console.ReadKey();
    }

    private static void PrintTree(Item item, int level)
    {
        PrintIndent(level);
        Console.Write("name = " + item.name);
        if (item.size != 0) {
            PrintIndent(level);
            Console.Write("size = " + item.size);
        }
        Console.WriteLine();
        foreach (var child in item.children) {
            PrintTree(child, level + 1);
        }
    }
    private static void PrintIndent(int level)
    {
        Console.Write(new String(' ', 4 * level));
    }
}

Upvotes: 2

evictednoise
evictednoise

Reputation: 593

There you go.

var filteredResult = result.Where(x => x.name != "test" || x.children.Count(c => c.name != "test") > 0 );

Selects rows where parent name isnt "test" OR any of children aren't "test"

Upvotes: 0

Related Questions