通过多个动态键将字典分组

时间:2019-12-06 01:00:17

标签: python

我有一个动态字典,每次都不相同,我想根据多个键将这个字典列表归为一组,一次为一个键,最后一次使用的键附加为sum float&int值。每次使用多键进行分组时都会进行分组,但是在分组的最后一次迭代中,我得到的形式是没有和的最终数据。

为了解释我在这里想要做的是一份字典示例列表(此示例不是静态的,字典的键/值对可能会更改):

[{'invoice_num': 'INV/2019/0012 ', 'tax_id': 'Tax 15.00%S', 'vat': False, 'total_amount': 805.0, 'fiscal_position_id': False, 'date': '2019-12-05', 'amount_exclude': 700.0, 'desc': '[AT] Air Flight', 'partner_id': 'Agrolait', 'amount_tax': 105.0, 'record_type': 'sale'}, {'invoice_num': 'INV/2019/0011 ', 'tax_id': 'Tax 15.00%S', 'vat': False, 'total_amount': 805.0, 'fiscal_position_id': False, 'date': '2019-12-05', 'amount_exclude': 700.0, 'desc': '[AT] Air Flight', 'partner_id': 'Agrolait', 'amount_tax': 105.0, 'record_type': 'sale'}, {'invoice_num': 'BILL/2019/0007 ', 'tax_id': 'Tax 15.00% P', 'vat': False, 'total_amount': 51750.0, 'fiscal_position_id': False, 'date': '2019-12-05', 'amount_exclude': 45000.0, 'desc': '[CONS_DEL02] Little server', 'partner_id': "Administrator, Pieter Parter's Farm", 'amount_tax': 6750.0, 'record_type': 'purchase'}, {'invoice_num': 'BILL/2019/0006 ', 'tax_id': 'Tax 15.00% P', 'vat': False, 'total_amount': 5749.99, 'fiscal_position_id': False, 'date': '2019-12-05', 'amount_exclude': 4999.99, 'desc': "Coffee Machine with huge 'employee's performances boosting perk'", 'partner_id': 'ASUSTeK', 'amount_tax': 750.0, 'record_type': 'purchase'}, {'invoice_num': 'BILL/2019/0002 ', 'tax_id': 'Tax 15.00% P', 'vat': False, 'total_amount': 5749.99, 'fiscal_position_id': False, 'date': '2019-11-15', 'amount_exclude': 4999.99, 'desc': "Coffee Machine with huge 'employee's performances boosting perk'", 'partner_id': 'ASUSTeK', 'amount_tax': 750.0, 'record_type': 'purchase'}]

我想分组:

['record_type', 'tax_id','partner_id']

因此,在第一组(按record_type)中,我希望将数据分组以便仅对值求和,然后在第二组(按record_type和tax_id)中,我要获取具有float&int值之和的值。第三组(按'record_type'&'tax_id'&'partner_id')我想要获取没有总和的记录,然后将其插入到xls文件中。

最终代表将是:

enter image description here

我试图一次将项目分组一次,但是我不能将具有相同元素的数据分组并在表中显示最后一项:

item_data = []
for item in group_by:
    final_data = [(a, list(b)) for a, b in
                  itertools.groupby([i.items() for i in records_read], key=lambda x: dict(x)[item])]
    new_final_data = [
        {i[0][0]: sum(c[-1] for c in i if isinstance(c[-1], float) or isinstance(c[-1], int)) if i[0][0] != item else
        i[0][-1] for i in
         zip(*b)} for a, b in final_data]
    item_data.append(new_final_data)

1 个答案:

答案 0 :(得分:1)

此脚本根据fields列表打印树:

data = [{'invoice_num': 'INV/2019/0012 ', 'tax_id': 'Tax 15.00%S', 'vat': 'Undefined', 'total_amount': 805.0, 'fiscal_position_id': 'Undefined', 'date': '2019-12-05', 'amount_exclude': 700.0, 'desc': '[AT] Air Flight', 'partner_id': 'Agrolait', 'amount_tax': 105.0, 'record_type': 'sale'}, {'invoice_num': 'INV/2019/0011 ', 'tax_id': 'Tax 15.00%S', 'vat': 'Undefined', 'total_amount': 805.0, 'fiscal_position_id': 'Undefined', 'date': '2019-12-05', 'amount_exclude': 700.0, 'desc': '[AT] Air Flight', 'partner_id': 'Agrolait', 'amount_tax': 105.0, 'record_type': 'sale'}, {'invoice_num': 'BILL/2019/0007 ', 'tax_id': 'Tax 15.00% P', 'vat': 'Undefined', 'total_amount': 51750.0, 'fiscal_position_id': 'Undefined', 'date': '2019-12-05', 'amount_exclude': 45000.0, 'desc': '[CONS_DEL02] Little server', 'partner_id': "Administrator, Pieter Parter's Farm", 'amount_tax': 6750.0, 'record_type': 'purchase'}, {'invoice_num': 'BILL/2019/0006 ', 'tax_id': 'Tax 15.00% P', 'vat': 'Undefined', 'total_amount': 5749.99, 'fiscal_position_id': 'Undefined', 'date': '2019-12-05', 'amount_exclude': 4999.99, 'desc': "Coffee Machine with huge 'employee's performances boosting perk'", 'partner_id': 'ASUSTeK', 'amount_tax': 750.0, 'record_type': 'purchase'}, {'invoice_num': 'BILL/2019/0002 ', 'tax_id': 'Tax 15.00% P', 'vat': 'Undefined', 'total_amount': 5749.99, 'fiscal_position_id': 'Undefined', 'date': '2019-11-15', 'amount_exclude': 4999.99, 'desc': "Coffee Machine with huge 'employee's performances boosting perk'", 'partner_id': 'ASUSTeK', 'amount_tax': 750.0, 'record_type': 'purchase'}]
fields = ['record_type', 'tax_id', 'partner_id', 'invoice_num']

from itertools import groupby
from operator import itemgetter

def group_by_fields(data, *fields):
f = itemgetter(*fields)
for v, g in groupby(sorted(data, key=f), f):
    g = list(g)
    float_keys = []
    for item in g:
        float_keys.extend(
            [key for key in item if isinstance(item[key], float) or isinstance(item[key], int)])
    float_keys = list(set(float_keys))
    yield (v,) if isinstance(v, str) else v, [sum(i[k] for i in g) for k in float_keys]


def print_tree(data, *fields):
    rv = []
    for i in range(1, len(fields)+1):
        rv.extend(group_by_fields(data, *fields[:i]))

    for v, g in groupby(sorted(rv, key=lambda k: (k[0], len(k[0])) ), lambda k: (k[0], len(k[0])) ):
        print('{:<60}'.format( (' ' * (v[1] * 4)) + v[0][-1]), end=' ')
        for item in g:
            print('{:<10.2f} {:<10.2f} {:<10.2f} '.format(*item[1][0:]))

print_tree(data, *fields)

打印:

purchase                                                 63249.98   54999.98   8250.00    
    Tax 15.00% P                                         63249.98   54999.98   8250.00    
        ASUSTeK                                          11499.98   9999.98    1500.00    
            BILL/2019/0002                               5749.99    4999.99    750.00     
            BILL/2019/0006                               5749.99    4999.99    750.00     
        Administrator, Pieter Parter's Farm              51750.00   45000.00   6750.00    
            BILL/2019/0007                               51750.00   45000.00   6750.00    
sale                                                     1610.00    1400.00    210.00     
    Tax 15.00%S                                          1610.00    1400.00    210.00     
        Agrolait                                         1610.00    1400.00    210.00     
            INV/2019/0011                                805.00     700.00     105.00     
            INV/2019/0012                                805.00     700.00     105.00