Python将带有列表(或带有字典的列表)的字典嵌套到用于CSV输出的平面字典列表

斯拉夫

我尝试搜索类似的问题,但发现的问题中没有一个可以满足我的需求。

我正在尝试构建一个可以使用2个参数的泛型函数:

  1. 对象结构
  2. (嵌套的)路径列表

并将所有给定路径转换为适合以CSV格式输出的平面字典列表。

因此,例如,如果我有一个结构,例如:

structure = {
    "configs": [
        {
            "name": "config_name",
            "id": 1,
            "parameters": [
                {
                    "name": "param name",
                    "description": "my description",
                    "type": "mytype",
                },
                {
                    "name": "test",
                    "description": "description 2",
                    "type": "myothertype",
                    "somedata": [
                        'data',
                        'data2'
                    ]
                }
            ]
        },
        {
            "name": "config_name2",
            "id": 2,
            "parameters": [
                {
                    "name": "param name",
                    "description": "my description",
                    "type": "mytype2",
                    "somedata": [
                        'data',
                        'data2'
                    ]
                },
                {
                    "name": "test",
                    "description": "description 2",
                    "type": "myothertype2",
                }
            ]
        }
    ]
}

并传递以下路径列表:

paths = [
'configs.name', # notice the list structure is omitted (i.e it should be 'configs.XXX.name' where XXX is the elem id). This means I want the name entry of every dict that is in the list of configs
'configs.0.id', # similar to the above but this time I want the ID only from the first config
'configs.parameters.type' # I want the type entry of every parameter of every config
]

由此,函数应生成一个平面字典列表。列表中的每个条目都对应于CSV的一行。每个平面词典都包含所有选定的路径。

因此,例如在这种情况下,我应该看到:

result = [
{"configs.name": "config_name", "configs.0.id": 1, "configs.parameters.type": "mytype"},
{"configs.name": "config_name", "configs.0.id": 1, "configs.parameters.type": "myothertype"},
{"configs.name": "config_name2", "configs.parameters.type": "mytype2"},
{"configs.name": "config_name2", "configs.parameters.type": "myothertype2"}
]

它需要能够对传递的包含嵌套字典和列表的任何结构进行此操作。

编辑:

我尝试了@ Ajax1234的代码,似乎有一个错误-在某些情况下,它获得的元素比预期的多两倍。以下代码演示了该错误:

已解决:问题由@ Ajax1234解决

import pprint


def get_val(d, rule, match = None, l_matches = []):
   if not rule:
      yield (l_matches, d)
   elif isinstance(d, list):
     if rule[0].isdigit() and (match is None or match[0] == int(rule[0])):
        yield from get_val(d[int(rule[0])], rule[1:], match=match if match is None else match[1:], l_matches=l_matches+[int(rule[0])])
     elif match is None or not rule[0].isdigit():
         for i, a in enumerate(d):
            if not match or i == match[0]:
               yield from get_val(a, rule, match=match if match is None else match[1:], l_matches = l_matches+[i])
   else:
      yield from get_val(d[rule[0]], rule[1:], match = match, l_matches = l_matches)

def evaluate(paths, struct, val = {}, rule = None):
   if not paths:
      yield val
   else:
      k = list(get_val(struct, paths[0].split('.'), match = rule))
      if k:
         for a, b in k:
            yield from evaluate(paths[1:], struct, val={**val, paths[0]:b}, rule = a)
      else:
         yield from evaluate(paths[1:], struct, val=val, rule=rule)
         
paths1 = ['configs.id', 'configs.parameters.name', 'configs.parameters.int-param'] # works as expected
paths2 = ['configs.parameters.name', 'configs.id', 'configs.parameters.int-param'] # prints everything twice

structure = {
    'configs': [
        {
            'id': 1,
            'name': 'declaration',
            'parameters': [
                {
                    'int-param': 0,
                    'description': 'decription1',
                    'name': 'name1',
                    'type': 'mytype1'
                },
                {
                    'int-param': 1,
                    'description': 'description2',
                    'list-param': ['param0'],
                    'name': 'name2',
                    'type': 'mytype2'
                }
            ]
        }
    ]
}

pprint.PrettyPrinter(2).pprint(list(evaluate(paths2, structure)))

使用paths1列表的输出为:

[ { 'configs.id': 1,
    'configs.parameters.int-param': 0,
    'configs.parameters.name': 'name1'},
  { 'configs.id': 1,
    'configs.parameters.int-param': 1,
    'configs.parameters.name': 'name2'}]

paths2产量的输出

[ { 'configs.id': 1,
    'configs.parameters.int-param': 0,
    'configs.parameters.name': 'name1'},
  { 'configs.id': 1,
    'configs.parameters.int-param': 1,
    'configs.parameters.name': 'name1'},
  { 'configs.id': 1,
    'configs.parameters.int-param': 0,
    'configs.parameters.name': 'name2'},
  { 'configs.id': 1,
    'configs.parameters.int-param': 1,
    'configs.parameters.name': 'name2'}]
阿贾克斯1234

您可以构建一个查找函数,该函数根据您的规则(get_val搜索值另外,此函数接收match有效索引的匹配列表(),该值告诉该函数仅遍历字典中具有匹配索引的子列表。这样,搜索功能可以从先前的搜索中“学习”,并且仅基于先前搜索的子列表位置返回值:

structure = {'configs': [{'name': 'config_name', 'id': 1, 'parameters': [{'name': 'param name', 'description': 'my description', 'type': 'mytype'}, {'name': 'test', 'description': 'description 2', 'type': 'myothertype', 'somedata': ['data', 'data2']}]}, {'name': 'config_name2', 'id': 2, 'parameters': [{'name': 'param name', 'description': 'my description', 'type': 'mytype2', 'somedata': ['data', 'data2']}, {'name': 'test', 'description': 'description 2', 'type': 'myothertype2'}]}]}
def get_val(d, rule, match = None, l_matches = []):
   if not rule:
      yield (l_matches, d)
   elif isinstance(d, list):
     if rule[0].isdigit() and (match is None or match[0] == int(rule[0])):
        yield from get_val(d[int(rule[0])], rule[1:], match=match if match is None else match[1:], l_matches=l_matches+[int(rule[0])])
     elif match is None or not rule[0].isdigit():
         for i, a in enumerate(d):
            if not match or i == match[0]:
               yield from get_val(a, rule, match=match if match is None else match[1:], l_matches = l_matches+[i])
   else:
      yield from get_val(d[rule[0]], rule[1:], match = match, l_matches = l_matches)

def evaluate(paths, struct, val = {}, rule = None):
   if not paths:
      yield val
   else:
      k = list(get_val(struct, paths[0].split('.'), match = rule))
      if k:
         for a, b in k:
            yield from evaluate(paths[1:], struct, val={**val, paths[0]:b}, rule = a)
      else:
         yield from evaluate(paths[1:], struct, val=val, rule = rule)

paths = ['configs.name', 'configs.0.id', 'configs.parameters.type']
print(list(evaluate(paths, structure)))

输出:

[{'configs.name': 'config_name', 'configs.0.id': 1, 'configs.parameters.type': 'mytype'}, 
 {'configs.name': 'config_name', 'configs.0.id': 1, 'configs.parameters.type': 'myothertype'}, 
 {'configs.name': 'config_name2', 'configs.parameters.type': 'mytype2'}, 
 {'configs.name': 'config_name2', 'configs.parameters.type': 'myothertype2'}]

编辑:最好按树中的路径深度对输入路径进行排序:

def get_depth(d, path, c = 0):
   if not path:
      yield c
   elif isinstance(d, dict) or path[0].isdigit():
      yield from get_depth(d[path[0] if isinstance(d, dict) else int(path[0])], path[1:], c+1)
   else:
      yield from [i for b in d for i in get_depth(b, path, c)]

此函数将在路径目标值所在的树中找到深度。然后,适用于主要代码:

structure = {'configs': [{'id': 1, 'name': 'declaration', 'parameters': [{'int-param': 0, 'description': 'decription1', 'name': 'name1', 'type': 'mytype1'}, {'int-param': 1, 'description': 'description2', 'list-param': ['param0'], 'name': 'name2', 'type': 'mytype2'}]}]}
paths1 = ['configs.id', 'configs.parameters.name', 'configs.parameters.int-param']
paths2 = ['configs.parameters.name', 'configs.id', 'configs.parameters.int-param']
print(list(evaluate(sorted(paths1, key=lambda x:max(get_depth(structure, x.split('.')))), structure)))
print(list(evaluate(sorted(paths2, key=lambda x:max(get_depth(structure, x.split('.')))), structure)))

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

python将带有子列表的列表转换为字典

来自分类Dev

带有字典列表的字典

来自分类Dev

如何将带有嵌套字典的列表写到csv文件中?

来自分类Dev

如何将带有嵌套字典的列表写到csv文件中?

来自分类Dev

带有嵌套列表的字典中的DataFrame

来自分类Dev

带有嵌套列表的字典中的DataFrame

来自分类Dev

Python-将字典列表变成带有列表的字典

来自分类Dev

带有值列表的Python中的嵌套字典理解

来自分类Dev

python将if和for函数用于带有列表的字典

来自分类Dev

带有元组Python列表的字典

来自分类Dev

将带有列表的字典转换为IEnumerable

来自分类Dev

使用python在csv中存储带有列表值的字典

来自分类Dev

定期将平面列表转换为带有键的字典

来自分类Dev

将带有列表的嵌套字典展开到pandas DataFrame-keys列中

来自分类Dev

将带有嵌套列表的字典转换为特定的熊猫df结构

来自分类Dev

tkinter - 将带有字典的嵌套列表中的数据添加到树视图

来自分类Dev

如何从Python列表中删除重复的字典(带有嵌套字典)?

来自分类Dev

带有嵌套词典列表的字典中的Pandas DataFrame

来自分类Dev

带有浮动错误的字典中的嵌套列表

来自分类Dev

Python / Pandas-将带有内部字典的列表转换为DataFrame

来自分类Dev

带有列表的字典中的Pandas DataFrame

来自分类Dev

使用递归构建带有列表的字典

来自分类Dev

发送字典列表作为带有请求的字典值

来自分类Dev

根据带有一个嵌套字典的键过滤字典列表

来自分类Dev

将列表嵌套到字典中

来自分类Dev

带有元组列表的嵌套字典作为来自python中DATA文件的值

来自分类Dev

对带有列表列表的字典进行操作

来自分类Dev

字典与嵌套字典的列表

来自分类Dev

Python将字典嵌套到reStructuredText项目符号列表中

Related 相关文章

  1. 1

    python将带有子列表的列表转换为字典

  2. 2

    带有字典列表的字典

  3. 3

    如何将带有嵌套字典的列表写到csv文件中?

  4. 4

    如何将带有嵌套字典的列表写到csv文件中?

  5. 5

    带有嵌套列表的字典中的DataFrame

  6. 6

    带有嵌套列表的字典中的DataFrame

  7. 7

    Python-将字典列表变成带有列表的字典

  8. 8

    带有值列表的Python中的嵌套字典理解

  9. 9

    python将if和for函数用于带有列表的字典

  10. 10

    带有元组Python列表的字典

  11. 11

    将带有列表的字典转换为IEnumerable

  12. 12

    使用python在csv中存储带有列表值的字典

  13. 13

    定期将平面列表转换为带有键的字典

  14. 14

    将带有列表的嵌套字典展开到pandas DataFrame-keys列中

  15. 15

    将带有嵌套列表的字典转换为特定的熊猫df结构

  16. 16

    tkinter - 将带有字典的嵌套列表中的数据添加到树视图

  17. 17

    如何从Python列表中删除重复的字典(带有嵌套字典)?

  18. 18

    带有嵌套词典列表的字典中的Pandas DataFrame

  19. 19

    带有浮动错误的字典中的嵌套列表

  20. 20

    Python / Pandas-将带有内部字典的列表转换为DataFrame

  21. 21

    带有列表的字典中的Pandas DataFrame

  22. 22

    使用递归构建带有列表的字典

  23. 23

    发送字典列表作为带有请求的字典值

  24. 24

    根据带有一个嵌套字典的键过滤字典列表

  25. 25

    将列表嵌套到字典中

  26. 26

    带有元组列表的嵌套字典作为来自python中DATA文件的值

  27. 27

    对带有列表列表的字典进行操作

  28. 28

    字典与嵌套字典的列表

  29. 29

    Python将字典嵌套到reStructuredText项目符号列表中

热门标签

归档