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

How to delete keys in a nested dictionary of lists based on the values

我正在处理一个代表树状结构的文件,该文件与 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

这似乎是您想要的近似值:

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'}]}]}

我刚刚编辑了@rchang 的 以修复 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