如何在Python的嵌套字典中获取层次结构下的项目?

时间:2018-08-04 22:33:57

标签: python dictionary

我有一个字典来自无限的子类别树结构。下面是示例;

    {
      "asset_id": 1566,
      "asset_name": "asset1",
      "asset_type": "A",
      "assets": [
        {
          "asset_id": 1255,
          "asset_name": "asset2",
          "asset_type": "A",
          "assets": [
            {
              "asset_id": 1472,
              "asset_name": "asset3",
              "asset_type": "A",
              "assets": []
            },
            {
              "asset_id": 1473,
              "asset_name": "asset4",
              "asset_type": "A",
              "assets": []
            }
          ]
        },
        {
          "asset_id": 1257,
          "asset_name": "asset5",
          "asset_type": "A",
          "assets": []
        },
        {
          "asset_id": 1259,
          "asset_name": "asset6",
          "asset_type": "A",
          "assets": []
        },
        {
          "asset_id": 1493,
          "asset_name": "asset7",
          "asset_type": "A",
          "assets": []
        }
      ]
    }

我想将所有项目都放在此树结构的一个类别下。 例如,“ asset_id” = 1255下的所有资产。

样本输出;

[
        {
          "asset_id": 1472,
          "asset_name": "asset3",
          "asset_type": "A",
          "assets": []
        },
        {
          "asset_id": 1473,
          "asset_name": "asset4",
          "asset_type": "A",
          "assets": []
        }
      ]

我该如何实现?

2 个答案:

答案 0 :(得分:1)

您可以使用递归:

d = {'asset_id': 1566, 'asset_name': 'asset1', 'asset_type': 'A', 'assets': [{'asset_id': 1255, 'asset_name': 'asset2', 'asset_type': 'A', 'assets': [{'asset_id': 1472, 'asset_name': 'asset3', 'asset_type': 'A', 'assets': []}, {'asset_id': 1473, 'asset_name': 'asset4', 'asset_type': 'A', 'assets': []}]}, {'asset_id': 1257, 'asset_name': 'asset5', 'asset_type': 'A', 'assets': []}, {'asset_id': 1259, 'asset_name': 'asset6', 'asset_type': 'A', 'assets': []}, {'asset_id': 1493, 'asset_name': 'asset7', 'asset_type': 'A', 'assets': []}]}
def get_assets(_d, below = 1255):
  if isinstance(_d, dict):
    if _d['asset_id'] == below:
      return _d['assets']
    _r = list(filter(None, [get_assets(i, below) for i in _d['assets']]))
    return _r[0] if _r else None

import json
print(json.dumps(get_assets(d), indent=4))

输出:

[
 {
    "asset_id": 1472,
    "asset_name": "asset3",
    "asset_type": "A",
    "assets": []
 },
 {
    "asset_id": 1473,
    "asset_name": "asset4",
    "asset_type": "A",
    "assets": []
  }
] 

答案 1 :(得分:1)

如果您希望能够查找所有以key=value格式指定的条件(例如asset_id=1255)匹配的所有资产对象,那么这可能对您有用。

def retrieve_assets(struct, **kwargs):
    def _rec(obj):
        if type(obj) is dict:
            if all(map(lambda k:obj.get(k) == kwargs.get(k), kwargs.keys())):
                return [obj]  #1
            else:
                return _rec(obj.get('assets'))  #2
        elif type(obj) is list:
            filtered = []
            for asset in obj:
                filtered.extend(_rec(asset))
            return filtered

    return _rec(struct)

您这样称呼它:

retrieve_assets(tree, asset_id=1255)

它使用内部函数递归地测试所有嵌套资产是否满足给定条件(在kwargs词典中作为键值对传递)。如果资产满足这些条件,它将全部返回给调用方(#1,包装在列表中)。如果不是,则内部函数将重复进行以测试子资产列表(#2)。

使用**kwargs命名的参数扩展机制不仅可以指定'asset_id'字段,还可以指定查找条件。您最好发出如下所示的呼叫:

retrieve_assets(tree, asset_type='B', assets=[])

这样,您将获得asset_type B且没有任何子项的所有资产对象的列表(即,它们的asset列表为空)自己。

编辑:在我答复之后,您明确表示只想检索满足指定条件的资产的后代资产。为了通过我的解决方案实现此目标,只需将标有#1的行更改为:

return obj.get('assets')  #1