简体   繁体   English

Python:如何将嵌套字典中的嵌套列表转换成字典

[英]Python: How to convert nested lists inside nested dicts into dicts

so I have this dict: 所以我有这个命令:

di = {'Type': ['Something1'],
      'details': [{'detail': [{'category': ['Stuff1'], 'value': ['Value1']},
                              {'category': ['Stuff2'], 'value': ['Value2']},
                              {'category': ['Stuff3'], 'value': ['Value3']},
                              {'category': ['Stuff3'], 'value': ['Value3']},
                              {'category': ['Stuff4'], 'value': ['Value4']}]}],
      'timestamp': ['2018-01-22 07:10:41']}

and would like to convert any list , except for any list of dicts not containing another list of dicts inside them, to a dict so that the end result would be: 并希望将除不包含其他 dict list of dicts任何dict list以外的任何list of dicts转换为dict以便最终结果为:

{'Type': 'Something1',
 'details': {'detail': [{'category': 'Stuff1', 'value': 'Value1'},
                        {'category': 'Stuff2', 'value': 'Value2'},
                        {'category': 'Stuff3', 'value': 'Value3'},
                        {'category': 'Stuff3', 'value': 'Value3'},
                        {'category': 'Stuff4', 'value': 'Value4'}]},
 'timestamp': '2018-01-22 07:10:41'}

So essentially, for any key whose value is a single item list , the value should drop the list component. 因此,从本质上讲,对于任何值为单个项目list ,该值都应删除list组件。

I've tried with the following recursive function without success: 我尝试使用以下递归函数未成功:

def delistdict(dicto):

    delisted = {}

    for k,v in dicto.items():

        if isinstance(v, list) and len(v) == 1:  
            delisted[k] = v[0]

        else:
            delisted[k] = delistdict(v)

    return {k:v if len(v) == 1 else v for k,v in delisted.items()}

It fails because it only removes the first instance of the list in {'detail': [(...)] (so just that outer [(...)] list) but it doesn't recurse to the remaining items. 它之所以失败,是因为它仅删除了{'detail': [(...)] list的第一个实例(因此仅删除了外部[(...)]列表),但没有递归到其余项。 So my result looks like this after running the script: 因此,运行脚本后,我的结果如下所示:

{'Type': 'Something1',
 'details': {'detail': [{'category': ['Stuff1'], 'value': ['Value1']},
                        {'category': ['Stuff2'], 'value': ['Value2']},
                        {'category': ['Stuff3'], 'value': ['Value3']},
                        {'category': ['Stuff3'], 'value': ['Value3']},
                        {'category': ['Stuff4'], 'value': ['Value4']}]},
 'timestamp': '2018-01-22 07:10:41'}

What should happen is that the single values inside the value and category keys should be converted to string s instead of remaining as single items within a list . 应该发生的是,应该将valuecategory键中的单个值转换为string s,而不是将其保留为list单个项。

Any ideas what I'm doing wrong? 有什么想法我做错了吗?

You can try this: 您可以尝试以下方法:

di = {'timestamp': ['2018-01-22 07:10:41'], 'Type': ['Something1'], 'details': [{'detail': [{'category': ['Stuff1'], 'value': ['Value1']}, {'category': ['Stuff2'], 'value': ['Value2']}, {'category': ['Stuff3'], 'value': ['Value3']}, {'category': ['Stuff3'], 'value': ['Value3']}, {'category': ['Stuff4'], 'value': ['Value4']}]}]}
def flatten(d):
  return {a:b[0] if len(b) == 1 and isinstance(b[0], str) else (flatten(b[0]) if len(b) == 1 and isinstance(b[0], dict) else [flatten(c) for c in b]) for a, b in d.items()}

Output: 输出:

{'timestamp': '2018-01-22 07:10:41', 'Type': 'Something1', 'details': {'detail': [{'category': 'Stuff1', 'value': 'Value1'}, {'category': 'Stuff2', 'value': 'Value2'}, {'category': 'Stuff3', 'value': 'Value3'}, {'category': 'Stuff3', 'value': 'Value3'}, {'category': 'Stuff4', 'value': 'Value4'}]}}

Non-comprehension solution: 非综合性解决方案:

def flatten(d):
   new_d = {}
   for a, b in d.items():
      if len(b) == 1 and isinstance(b[0], str):
          new_d[a] = b[0]
      elif len(b) == 1 and isinstance(b[0], dict):
          new_d[a] = flatten(b[0])
      else:
          temp_list = []
          for c in b:
             temp_list.append(flatten(c))
          new_d[a] = temp_list
   return new_d

Output: 输出:

{'timestamp': '2018-01-22 07:10:41', 'Type': 'Something1', 'details': {'detail': [{'category': 'Stuff1', 'value': 'Value1'}, {'category': 'Stuff2', 'value': 'Value2'}, {'category': 'Stuff3', 'value': 'Value3'}, {'category': 'Stuff3', 'value': 'Value3'}, {'category': 'Stuff4', 'value': 'Value4'}]}}

I didn't spend the time to optimize the code, but I modified your original function to do the trick: 我没有花时间来优化代码,但我修改了您的原始函数来解决问题:

def delistdict(dicto):

    delisted = {}

    for k, v in dicto.items():

        if isinstance(v, list):
            lst = []
            for i in v:
                if isinstance(i, dict):
                    lst.append(delistdict(i))
                else:
                    lst.append(i)
            delisted[k] = lst[0] if len(lst) == 1 else lst
        elif isinstance(v, dict):
            delisted[k] = delistdict(v)
        else:
            delisted[k] = v

    return {k:v if len(v) == 1 else v for k,v in delisted.items()}

Output (pretty printed): 输出(漂亮打印):

{'Type': 'Something1',
 'details': {'detail': [{'category': 'Stuff1', 'value': 'Value1'},
                        {'category': 'Stuff2', 'value': 'Value2'},
                        {'category': 'Stuff3', 'value': 'Value3'},
                        {'category': 'Stuff3', 'value': 'Value3'},
                        {'category': 'Stuff4', 'value': 'Value4'}]},
 'timestamp': '2018-01-22 07:10:41'}

The issue was your function assumed all list should have len 1, otherwise it just returns the delisted dictionary, which still have nested list s inside unprocessed. 问题是您的函数假定所有list都应为len 1,否则它仅返回已删除list的字典,该字典仍具有未处理的嵌套list s。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM