从复合列表中过滤掉对象C#

时间:2015-07-15 15:51:51

标签: c# linq list

我有一个复合列表如下 -

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

使用以下模型 -

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

现在,我想过滤掉名称= test的所有对象及其子对象。因此,如果父节点的名称= test且子名称不是= test,我仍然需要父节点。

所以,如果我有一个数据,如 -

{
    "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 }
            ]
        }
    ]
}

所需的输出是 -

{
    "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 }
            ]
        }
    ]
}

编辑 -

澄清一些问题。

由于父母的名字是Test,我希望拥有整个节点及其所有子节点。因此存在Test1和Test2。

如果父节点的名称不是test,但是有一个名为Test的子节点,那么我希望节点只包含名为Test的子元素。

编辑2

情景 -

  1. 如果父项名为“Test”,请保留它及其所有子项。
  2. 如果父项目未命名为“测试”但有任何名为“测试”的子项,则只需保留该项目名称为“测试”的子项并删除其余子项
  3. 否则删除该项目。

2 个答案:

答案 0 :(得分:2)

如果您在所有级别使用相同的类,则可以使用递归方法。假设班级

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

我们可以做到

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);
        }
    }
}

调用它
PruneTree(result);

<强>更新

在您的澄清之后是另一个满足以下规则的解决方案:

  1. 如果某个项目名为“Test”,请保留该项及其所有子项。
  2. 如果某个项目有任何名为“Test”的孩子,请保留它。
  3. 否则删除该项目。
  4. 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);
                }
            }
        }
    }
    

    在调用PruneTree之前和之后测试输出: enter image description here

    这是我的整个测试课程:

    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));
        }
    }
    

答案 1 :(得分:0)

你去。

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

选择父名称不是&#34; test&#34;的行。或者任何一个孩子都没有&#34;测试&#34;