Python过滤器嵌套的dict给出了键名列表

时间:2014-04-22 21:56:13

标签: python recursion

有没有办法在Python中过滤嵌套的dict,所以我只能看到我指定的键? 例如:

x = {
  "field": [
    {
      "nm_field": "ch_origem_sistema_chave",
      "inf_tabelado": {
        "dropdown_value": "",
        "dropdown_key": "",
        "url_lista": "",
        "chave_relacional": ""
      },
    },
    {
      "nm_field": "ax_andamento_data",
      "inf_tabelado": {
        "dropdown_value": "",
        "dropdown_key": "",
        "url_lista": "",
        "chave_relacional": ""
      },
    }
  ],
  "_metadata": {
    "dt_reg": "22/01/2014 16:17:16",
    "dt_last_up": "10/04/2014 16:30:44",
  },
  "url_detalhes": "/DetalhesDocsPro.aspx",
  "url_app": "/docspro",
}

y = filter(x, ['dropdown_value', 'nm_field', 'url_app', 'dt_reg'])

然后var y就像:

{
  "field": [
    {
      "nm_field": "ch_origem_sistema_chave",
      "inf_tabelado": {
        "dropdown_value": "",
      },
    },
    {
      "nm_field": "ax_andamento_data",
      "inf_tabelado": {
        "dropdown_value": "",
      },
    }
  ],
  "_metadata": {
    "dt_reg": "22/01/2014 16:17:16",
  },
  "url_app": "/docspro",
}

我尝试使用defaultdict做一些事情,但在任何递归级别的列表都没有成功。我在使用不同的数据结构时也发现了很多困难。

2 个答案:

答案 0 :(得分:2)

这是一个解决方案,它以深度优先的方式遍历结构,以找到您正在检查的“叶子”节点,以查看它们是否在您要保留的元素列表中。当它找到这样的元素时,它会使用del将其从字典中删除。 (所以这是就地完成的。)

def fltr(d, vals):
    if isinstance(d, dict):
        vals_to_del = []
        for k in d:
            if k in vals:
                continue
            if not isinstance(d[k], list) and not isinstance(d[k], dict):
                if k not in vals:
                    vals_to_del.append(k)
            else:
                fltr(d[k], vals)
        for k in vals_to_del:
            del d[k]
    elif isinstance(d, list):
        for i in d:
            fltr(i, vals)

请注意,我没有定义一个名为filter的函数,因为它是一个内置的函数,你不想暗示它。

>>> fltr(x, ['dropdown_value', 'nm_field', 'url_app', 'dt_reg'])
>>> x
{'field': [{'inf_tabelado': {'dropdown_value': ''}, 'nm_field': 'ch_origem_sistema_chave'}, {'inf_tabelado': {'dropdown_value': ''}, 'nm_field': 'ax_andamento_data'}], 'url_app': '/docspro', '_metadata': {'dt_reg': '22/01/2014 16:17:16'}}

答案 1 :(得分:1)

这是2rs2ts的答案的修改版本,它返回一个新对象而不是修改旧对象(并处理非叶子节点上的过滤):

import copy

def fltr(node, vals):
    if isinstance(node, dict):
        retVal = {}
        for key in node:
            if key in vals:
                retVal[key] = copy.deepcopy(node[key])
            elif isinstance(node[key], list) or isinstance(node[key], dict):
                child = fltr(node[key], vals)
                if child:
                    retVal[key] = child
        if retVal:
             return retVal
        else:
             return None
    elif isinstance(node, list):
        retVal = []
        for entry in node:
            child = fltr(entry, vals)
            if child:
                retVal.append(child)
        if retVal:
            return retVal
        else:
            return None

有了这个,你会打电话给

y = fltr(x, ['dropdown_value', 'nm_field', 'url_app', 'dt_reg'])

并获取

{
    "field": [
        {
            "inf_tabelado": {
                "dropdown_value": ""
            },
            "nm_field": "ch_origem_sistema_chave"
        },
        {
            "inf_tabelado": {
                "dropdown_value": ""
            },
            "nm_field": "ax_andamento_data"
        }
    ],
    "url_app": "/docspro",
    "_metadata": {
        "dt_reg": "22/01/2014 16:17:16"
    }
}

请注意,如果所有内容都已过滤,则会返回None。例如,

fltr(x, [])
无论None中的内容如何,​​

始终会返回x