如何根据值删除嵌套的列表字典中的键

时间:2015-01-27 10:51:42

标签: python recursion dictionary tree

我正在处理一个表示类似于flare.json的树状结构的文件,这个结构以D3.js社区而闻名。在python中删除树的所有叶子的最佳方法是什么?换句话说,我想删除其值中没有'children'键的所有键。

示例:

{
 "name": "flare",
 "children": [
  {
   "name": "analytics",
   "children": [
    {
     "name": "cluster",
     "children": [
      {"name": "AgglomerativeCluster", "size": 3938},
      {"name": "CommunityStructure", "size": 3812},
      {"name": "HierarchicalCluster", "size": 6714},
      {"name": "MergeEdge", "size": 743}
     ]
    },
    {
     "name": "graph",
     "children": [
      {"name": "BetweennessCentrality", "size": 3534},
      {"name": "LinkDistance", "size": 5731},
      {"name": "MaxFlowMinCut", "size": 7840},
      {"name": "ShortestPaths", "size": 5914},
      {"name": "SpanningTree", "size": 3416}
     ]
    },
    {
     "name": "optimization",
     "children": [
      {"name": "AspectRatioBanker", "size": 7074}
     ] ...

应该成为:

{
 "name": "flare",
 "children": [
  {
   "name": "analytics",
   "children": [
    {
     "name": "cluster",
    },
    {
     "name": "graph",
    },
    {
     "name": "optimization",

     ] ...

换句话说,我只是砍掉了树的叶子。在子列表中为空,应将其删除。

我试过这只是为了删除密钥,它不起作用:

def deleteLeaves(pTree):
    if pTree.has_key('children'):
        for child in pTree['children']:
            deleteLeaves(child)
    else:
        del pTree

2 个答案:

答案 0 :(得分:1)

这似乎接近你想要的东西:

def pruneLeaves(obj):

  if isinstance(obj, dict):
    isLeaf = True
    for key in obj.keys():
      if key == 'children': isLeaf = False
      if pruneLeaves(obj[key]): del obj[key]
    return isLeaf

  elif isinstance(obj, list):
    leaves = []
    for (index, element) in enumerate(obj):
      if pruneLeaves(element): leaves.append(index)
    leaves.reverse()
    for index in leaves: obj.pop(index)
    return not bool(obj)

  else:  # String values look like attributes in your dict, so never prune them
    return False

使用截断的数据样本进行测试:

data = {
 "name": "flare",
 "children": [
  {
   "name": "analytics",
   "children": [
    {
     "name": "cluster",
     "children": [
      {"name": "AgglomerativeCluster", "size": 3938},
      {"name": "CommunityStructure", "size": 3812},
      {"name": "HierarchicalCluster", "size": 6714},
      {"name": "MergeEdge", "size": 743}
     ]
    },
    {
     "name": "graph",
     "children": [
      {"name": "BetweennessCentrality", "size": 3534},
      {"name": "LinkDistance", "size": 5731},
      {"name": "MaxFlowMinCut", "size": 7840},
      {"name": "ShortestPaths", "size": 5914},
      {"name": "SpanningTree", "size": 3416}
     ]
    }
   ]
  }
  ]
}

pruneLeaves(data)
print data

得到了这些结果:

{'name': 'flare', 'children': [{'name': 'analytics', 'children': [{'name': 'cluster'}, {'name': 'graph'}]}]}

答案 1 :(得分:1)

我刚刚编辑了@rchang的answer来修正除children以外的列表的删除。

def pruneLeaves(self,obj):
    if isinstance(obj, dict):
        isLeaf = True
        for key in obj.keys():
            if key=='children': 
                isLeaf = False
                if self.pruneLeaves(obj[key]): del obj[key]
        return isLeaf

    elif isinstance(obj, list) :
        leaves = []
        for (index, element) in enumerate(obj):
          if self.pruneLeaves(element): leaves.append(index)
        leaves.reverse()
        for index in leaves: obj.pop(index)
        return not bool(obj)
    else:  # String values look like attributes in your dict, so never prune them
        return False