【问题标题】:Dictionary Splitting/Comprehension字典拆分/理解
【发布时间】:2020-06-05 14:03:07
【问题描述】:

我有一本字典,我想将其拆分成一个字典列表,以便将提交内容添加到数据库中。

这是字典,这不是静态字典,它是动态生成的,所以数字可以增加

# notice the keys are all grouped by numbers, 

 data = {'resident_payer,1': 'William Brown',
        'Term Fee,amount_paid,1': '1',
        'method,1': 'credit',
        'document_id,1': '1',

        'resident_payer,2': None,
        'Term Fee,amount_paid,2': '0',
        'method,2': 'other',
        'document_id,2': '0'}

我需要一个如下所示的字典列表:

[
{'resident_payer': 'William Brown', 'Term Fee,amount_paid': '1', 'method': 'credit', 'document_id': '1'},
{'resident_payer': None, 'Term Fee_amount_paid': '0', 'method': 'other', 'document_id': '0'}
]

如何通过 dict 理解以简单的方式做到这一点?

这里是工作代码,但如果我使用和清除循环外声明的变量时看起来很奇怪的复杂性,我无法找出解决方案,所以我想要一种更清晰的 Py​​thonic 方式来编写它。

data = {'resident_payer,1': 'William Brown',
        'Term Fee,amount_paid,1': '1',
        'method,1': 'credit',
        'document_id,1': '1',

        'resident_payer,2': None,
        'Term Fee,amount_paid,2': '0',
        'method,2': 'other',
        'document_id,2': '0'}

# will hold broken down lists
list_of_submissions = list()
# used to parse data into separated list of dictionaries.
# The key is split into numbers for grouping
current_loop = 1
active_dict_to_add_to_list = dict()
for key, value in data.items():
    if f'{current_loop}' in key:
        # we are in the current iteration
        # add the item to the active dict, the key is split by the ',' and [1] is the number so [0] needs to be selected
        # slice by 0: -1 to get first to everything but last element
        key_to_use = ",".join(key.split(',')[0:-1])

        active_dict_to_add_to_list[key_to_use] = value
        print(active_dict_to_add_to_list)
        # I know the dict should be 4 in length s I can realize I need to add here, but I don't like that...
        if len(active_dict_to_add_to_list) == 4:
            list_of_submissions.append(active_dict_to_add_to_list)
            # print('added', active_dict_to_add_to_list)
            active_dict_to_add_to_list = dict()
            current_loop += 1
    else:
        # we need to move to new iteration
        # add the current active dict to the list of submissions
        list_of_submissions.append(active_dict_to_add_to_list)
        print('added', active_dict_to_add_to_list)
        # clear the active dict so it can be added again
        active_dict_to_add_to_list = dict()
        current_loop += 1

print(list_of_submissions)

【问题讨论】:

    标签: python dictionary dictionary-comprehension


    【解决方案1】:

    您可以使用itertools.groupby:

    from itertools import groupby
    [{k.split(',')[0]: v for k, v in g} for i, g in groupby(data.items(), key=lambda x: x[0].split(',')[-1])]
    

    结果:

    [{'resident_payer': 'William Brown', 'Term Fee': '1', 'method': 'credit', 'document_id': '1'},
     {'resident_payer': None, 'Term Fee': '0', 'method': 'other', 'document_id': '0'}]
    

    【讨论】:

      【解决方案2】:
      data = {'resident_payer,1': 'William Brown',
              'Term Fee,amount_paid,1': '1',
              'method,1': 'credit',
              'document_id,1': '1',
      
              'resident_payer,2': None,
              'Term Fee,amount_paid,2': '0',
              'method,2': 'other',
              'document_id,2': '0'}
      
      out = {}
      for k, v in data.items():
          # all but last element
          key_to_use = ",".join(k.split(',')[0:-1])
          out.setdefault(k.split(',')[-1], {})[key_to_use] = v
      
      out = list(out.values())
      
      print(out)
      

      打印:

      [{'resident_payer': 'William Brown', 'Term Fee': '1', 'method': 'credit', 'document_id': '1'}, {'resident_payer': None, 'Term Fee': '0', 'method': 'other', 'document_id': '0'}]
      

      【讨论】:

      • 我添加了一个更改,基本上使k.split(',')[-1] 变成k.split(',')[0:-1](当你写这个答案时,我在最初的帖子中有一个逻辑错误),但我不在乎你是否自己改变它,这是一个更清洁的解决方案!
      【解决方案3】:

      这是我可以合理减少的程度:

      from pprint import pprint
      
      data = {'resident_payer,1': 'William Brown',
              'Term Fee,amount_paid,1': '1',
              'method,1': 'credit',
              'document_id,1': '1',
      
              'resident_payer,2': None,
              'Term Fee,amount_paid,2': '0',
              'method,2': 'other',
              'document_id,2': '0'}
      
      out1 = {}
      for k, v in data.items():
          newk, subid = k.rsplit(",", 1)
          out1.setdefault(subid, {})[newk] = v
      
      out = [out1[k] for k in sorted(out1.keys(), key=int)]
      
      pprint(out)
      

      给予:

      [{'Term Fee,amount_paid': '1',
        'document_id': '1',
        'method': 'credit',
        'resident_payer': 'William Brown'},
       {'Term Fee,amount_paid': '0',
        'document_id': '0',
        'method': 'other',
        'resident_payer': None}]
      

      这是假设您希望输出列表按照用于对条目进行分组的数字(在中间字典 out1 中用作键)排序。

      【讨论】:

        【解决方案4】:

        试试这个,KeyError 用完所有索引就打破循环。

        start_index, parsed_dict = 1, []
        
        keys = ["resident_payer", "Term Fee,amount_paid",
                "Term Fee,amount_paid", "method", "document_id"]
        
        while True:
            try:
                for key in keys:
                    parsed_dict.append({key: data[key + "," + str(start_index)]})
            except KeyError:
                break
        
            start_index += 1
        
        print(parsed_dict)
        

        输出,

        [{'resident_payer': 'William Brown'}, {'Term Fee,amount_paid': '1'}, {'Term Fee,amount_paid': '1'}, {'method': 'credit'}, {'document_id': '1'}, 
        {'resident_payer': None}, {'Term Fee,amount_paid': '0'}, {'Term Fee,amount_paid': '0'}, {'method': 'other'}, {'document_id': '0'}]
        

        【讨论】:

        • 这没有提供正确的输出,这使得在组中使用这些数据几乎不可能,因为这不再支持多个字段之间的分组关系......但这是一种有趣的方法
        • @ViaTech,只是想知道上面的代码会失败吗?
        • 您有一个字典列表,其中只有一个键、值对。正如我在帖子中所说,这是一个数据库条目,并且有一个带有附加到键的初始数字的分组。使用您提供的解决方案,如何知道哪个resident_payer(或分组中的任何其他字段)支付了多少金额?