如何添加到字典中,但过滤掉空键

本文关键字:过滤 字典 何添加 添加 | 更新日期: 2023-09-27 18:03:06

这个问题中的代码生成以下JSON:

由于.Where(a => a.Values != null)行,代码应该排除空的"Children"键,但是它不起作用。

我在哪里可以放置Where子句,以便JSON不包括一堆空的"子"数组?

谢谢你的帮助。

[{
        "NodeID" : 1,
        "NodeText" : "Country",
        "Children" : [{
                "NodeID" : 3,
                "NodeText" : "President",
                "Children" : []
            }, {
                "NodeID" : 4,
                "NodeText" : "Population",
                "Children" : []
            }, {
                "NodeID" : 5,
                "NodeText" : "State",
                "Children" : [{
                        "NodeID" : 6,
                        "NodeText" : "Governor",
                        "Children" : []
                    }, {
                        "NodeID" : 7,
                        "NodeText" : "Population",
                        "Children" : []
                    }, {
                        "NodeID" : 8,
                        "NodeText" : "County",
                        "Children" : [{
                                "NodeID" : 9,
                                "NodeText" : "Population",
                                "Children" : []
                            }
                        ]
                    }
                ]
            }
        ]
    }, {
        "NodeID" : 2,
        "NodeText" : "Year",
        "Children" : []
    }
]
下面是生成上述JSON的示例代码:
public class Node
{
    public int? ParentNodeID { get; set; }
    public int NodeID { get; set; }
    public string NodeText { get; set; }
    public Node(int? parentNodeID, int nodeID, string nodeText)
    {
        ParentNodeID = parentNodeID;
        NodeID = nodeID;
        NodeText = nodeText;
    }
}
public List<Dictionary<string, object>> BuildTree(int? parentNodeID = null, List<Node> exampleData = null)
{
    // kickstart the recursion with example data
    if (exampleData == null)
    {
        exampleData = new List<Node>();
        exampleData.Add(new Node(null, 1, "Country"));
        exampleData.Add(new Node(null, 2, "Year"));
        exampleData.Add(new Node(1, 3, "President"));
        exampleData.Add(new Node(1, 4, "Population"));
        exampleData.Add(new Node(1, 5, "State"));
        exampleData.Add(new Node(5, 6, "Governor"));
        exampleData.Add(new Node(5, 7, "Population"));
        exampleData.Add(new Node(5, 8, "County"));
        exampleData.Add(new Node(8, 9, "Population"));
    }
    List<Dictionary<string, object>> result = new List<Dictionary<string, object>>();
    var nodes = exampleData.Where(a => a.ParentNodeID == parentNodeID).ToList();
    if (nodes != null)
    {
        result.AddRange(nodes
            .Select(a => new Dictionary<string, object> {
                { "NodeID", a.NodeID},
                { "NodeText", a.NodeText },
                { "Children", BuildTree(a.NodeID, exampleData) }
            })
            .Where(a => a.Values != null) // this doesn't have any effect
            .ToList()
        );
    }
    return result;
}

如何添加到字典中,但过滤掉空键

问题是您总是创建一个包含"Children"值的Dictionary,即使没有child。

解决方案是将其放入一个条件中,如果没有子元素,则不添加该值,否则无论如何都要添加带有空集合值的children Key。

下面是为我完成这个工作的代码:肉和土豆是现在在递归语句中调用的Func<T> getNodeDictionary

    public static List<Dictionary<string, object>> BuildTree(int? parentNodeID = null, List<Node> exampleData = null)
    {
        // kickstart the recursion with example data
        if (exampleData == null)
        {
            exampleData = new List<Node>();
            exampleData.Add(new Node(null, 1, "Country"));
            exampleData.Add(new Node(null, 2, "Year"));
            exampleData.Add(new Node(1, 3, "President"));
            exampleData.Add(new Node(1, 4, "Population"));
            exampleData.Add(new Node(1, 5, "State"));
            exampleData.Add(new Node(5, 6, "Governor"));
            exampleData.Add(new Node(5, 7, "Population"));
            exampleData.Add(new Node(5, 8, "County"));
            exampleData.Add(new Node(8, 9, "Population"));
        }
        List<Dictionary<string, object>> result = new List<Dictionary<string, object>>();
        var nodes = exampleData.Where(a => a.ParentNodeID == parentNodeID).ToList();
        if (nodes != null)
        {
            Func<Node, Dictionary<string, object>> getNodeDictionary = n => {
                var children = BuildTree(n.NodeID, exampleData); // still recursive
                var returnDictionary = new Dictionary<string, object> { // these 2 nodes always get added
                    { "NodeID", n.NodeID},
                    { "NodeText", n.NodeText }
                };
                // This ensures we only add Children if there are actually any children
                if (children.Any())
                {
                    returnDictionary.Add("Children", children);
                }
                return returnDictionary;
            };
            // No need for where clause since we now do not add the empty elements
            result.AddRange(nodes
                .Select(a => getNodeDictionary(a))
                .ToList()
            );
        }
        return result;
    }

想想这里发生了什么。你有:

result.AddRange(nodes
    .Select(a => new Dictionary<string, object> {
        { "NodeID", a.NodeID},
        { "NodeText", a.NodeText },
        { "Children", BuildTree(a.NodeID, exampleData) }
    })
    .Where(a => a.Values != null) // this doesn't have any effect
    .ToList()
);

Where正在检查您创建的新项目,而不是节点。就像说:

var temp1 = nodes.Select(a => new Dictionary<string, object> { ... });
var temp2 = temp1.Where(a => a.Values != null);
result.AddRange(temp2);

所以temp1是一堆匿名对象实例,所有这些实例都包含一个字典,其中有三个键/值对。

我认为你想要的是:

.Where(a => a["Children"] != null)

当然,假设BuildTree对空列表返回null

.Where(a => a.Values != null)中的Values对于子代总是不为空,因为您是在递归({ "Children", BuildTree(a.NodeID, exampleData) })中初始化它。更改Where条件以检查空子节点。

你可以添加方法:

    private static bool IsNotEmptyTree(object value)
    {
        if (value == null) return false;  //Is empty whatever
        if (value as List<Dictionary<string, object>> != null)
        {
            var dict = (value as List<Dictionary<string, object>>);
            return dict.Count > 0;
        }
        // not empty
        return true;
    }

在Where:

.Where(a => a.Values.All(IsNotEmptyTree))