Reputation: 552
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 -
Upvotes: 0
Views: 289
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:
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:
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
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