如何将AddRange添加到字典但过滤掉空键?

时间:2013-03-08 19:45:32

标签: c# json dictionary

此问题中的代码生成以下JSON。

代码应该通过行.Where(a => a.Values != null)排除空的“子”键,但它不起作用。

我可以在哪里放置where子句,以便JSON不包含一堆空的“Children”数组?

感谢您的帮助。

[{
        "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;
}

3 个答案:

答案 0 :(得分:2)

问题在于,即使没有孩子,您也总是创建一个包含值“Children”的词典。

解决方法是将其置于一个条件中,如果没有子节点则不添加值,否则无论如何都不断添加带有空集合值的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;
    }

答案 1 :(得分:0)

Values中的{p> .Where(a => a.Values != null)对于孩子来说始终不为空,因为您在递归({ "Children", BuildTree(a.NodeID, exampleData) })中正在使用它。改变检查空子的条件。

您可以添加方法:

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

答案 2 :(得分:0)

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

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