将字典的Python列表转换为按键分组的字典排序列表

时间:2019-03-17 08:33:46

标签: python dictionary

我需要有关在Python中按键对字典列表进行分组的帮助。我有字典列表:

raw_values = [
              {'qty': 1, 'price': 11.0, 'name': 'Name 1', 'id': '111'},
              {'qty': 2, 'price': 22.0, 'name': 'Name 2', 'id': '111'},
              {'qty': 3, 'price': 33.0, 'name': 'Name 3', 'id': '111'},
              {'qty': 0, 'price': 12.0, 'name': 'Name 1', 'id': '222'},
              {'qty': 3, 'price': 13.0, 'name': 'Name 2', 'id': '222'},
              {'qty': 7, 'price': 14.0, 'name': 'Name 2', 'id': '333'},
              {'qty': 10, 'price': 15.0, 'name': 'Name 3', 'id': '333'}]

基于该列表,我需要创建一个新的词典列表,在该列表中,我可以按“ id”键对记录进行分组,还可以正确重命名并填充其他列-name和qty(如果某些“ id”不是任何记录)我需要将它们留空)。所需的输出:

sorted_values = [
                {"id": "111",
                 "name_1_price": 11.0, "name_1_qty": 1,
                 "name_2_price": 22.0, "name_2_qty": 2,
                 "name_3_price": 33.0, "name_3_qty": 3},
                {"id": "222",
                 "name_1_price": 12.0, "name_1_qty": 0,
                 "name_2_price": 13.0, "name_2_qty": 3,
                 "name_3_price": None, "name_3_qty": None
                 },
                {"id": "333",
                 "name_1_price": None, "name_1_qty": None,
                 "name_2_price": 14, "name_2_qty": 7,
                 "name_3_price": 15.0, "name_3_qty": 10
                 }
               ]

我试图搜索解决方案,我认为我需要使用itertools.groupby函数来按'id'键进行分组。 但是我不知道-如何根据'id'分组并根据'name'中的值重命名和填充字典?

3 个答案:

答案 0 :(得分:0)

Pandas解决方案:

import pandas as pd

raw_values = [
              {'qty': 1, 'price': 11.0, 'name': 'Name 1', 'id': '111'},
              {'qty': 2, 'price': 22.0, 'name': 'Name 2', 'id': '111'},
              {'qty': 3, 'price': 33.0, 'name': 'Name 3', 'id': '111'},
              {'qty': 0, 'price': 12.0, 'name': 'Name 1', 'id': '222'},
              {'qty': 3, 'price': 13.0, 'name': 'Name 2', 'id': '222'},
              {'qty': 7, 'price': 14.0, 'name': 'Name 2', 'id': '333'},
              {'qty': 10, 'price': 15.0, 'name': 'Name 3', 'id': '333'}]

#create DataFrame from dictionary
df = pd.DataFrame(raw_values)
print (df)
    id    name  price  qty
0  111  Name 1   11.0    1
1  111  Name 2   22.0    2
2  111  Name 3   33.0    3
3  222  Name 1   12.0    0
4  222  Name 2   13.0    3
5  333  Name 2   14.0    7
6  333  Name 3   15.0   10

#change value to lower and replace empty spaces
df['name'] = df['name'].str.lower().str.replace('\s+','_')
#reshape by unstack, sorting
df = df.set_index(['id','name']).unstack().sort_index(level=1, axis=1).swaplevel(1,0,axis=1)
#flatten MultiIndex 
df.columns = df.columns.map('_'.join)
df = df.reset_index()
#convert NaN to None
df = df.mask(df.isnull(), None)

#convert to list of dicts
L = df.to_dict(orient='records')
print (L)
[{'id': '111', 
  'name_1_price': 11.0, 'name_1_qty': 1.0, 
  'name_2_price': 22.0, 'name_2_qty': 2.0, 
  'name_3_price': 33.0, 'name_3_qty': 3.0}, 
 {'id': '222', 
  'name_1_price': 12.0, 'name_1_qty': 0.0, 
  'name_2_price': 13.0, 'name_2_qty': 3.0, 
  'name_3_price': None, 'name_3_qty': None}, 
 {'id': '333', 
  'name_1_price': None, 'name_1_qty': None, 
  'name_2_price': 14.0, 'name_2_qty': 7.0, 
  'name_3_price': 15.0, 'name_3_qty': 10.0}]

答案 1 :(得分:0)

您可以执行以下操作(在纯python中):

grouped  = {}
for row in raw_values:
    if row['id'] not in grouped:
        grouped[row['id']] = []
    grouped[row['id']].append((row['qty'], row['price'], row['name']))


output = []
for ID in grouped:
    item = {'id': ID}
    for (q, p, n) in grouped[ID]:
        item[n + '_qty'] = q
        item[n + '_price'] = p
    output.append(item)

print(output)

输出将是:

[{'Name 1_qty': 0, 'id': '222', 'Name 2_qty': 3, 'Name 2_price': 13.0, 'Name 1_price': 12.0}, {'Name 1_qty': 1, 'id': '111', 'Name 2_  
qty': 2, 'Name 3_price': 33.0, 'Name 3_qty': 3, 'Name 1_price': 11.0, 'Name 2_price': 22.0}, {'Name 3_price': 15.0, 'id': '333', 'Nam  
e 2_qty': 7, 'Name 3_qty': 10, 'Name 2_price': 14.0}]

答案 2 :(得分:0)

很简单,但这是我的解决方案。您可以自定义数量名称的数量:

def byId(el):
    return el['id']
raw_values = [
              {'qty': 1, 'price': 11.0, 'name': 'Name 1', 'id': '111'},
              {'qty': 2, 'price': 22.0, 'name': 'Name 2', 'id': '111'},
              {'qty': 3, 'price': 33.0, 'name': 'Name 3', 'id': '111'},
              {'qty': 0, 'price': 12.0, 'name': 'Name 1', 'id': '222'},
              {'qty': 3, 'price': 13.0, 'name': 'Name 2', 'id': '222'},
              {'qty': 7, 'price': 14.0, 'name': 'Name 2', 'id': '333'},
              {'qty': 10, 'price': 15.0, 'name': 'Name 3', 'id': '333'}]
names = 3
vals = {el['id']:[] for el in raw_values}
for key in vals.keys():
    vals[key] = [{f'name_{i+1}_price':None,f'name_{i+1}_qty':None} for i in range(names)]
for el in raw_values:
    i = el['name'][-1]
    vals[el['id']][int(i)-1][f'name_{i}_price'] = el['price']
    vals[el['id']][int(i)-1][f'name_{i}_qty'] = el['qty']
sorted_vals = []
for i,lsts in vals.items():
    element = {"id":i}
    for el in lsts:
        element = {**element, **el}
    sorted_vals.append(element)
sorted_vals = sorted(sorted_vals,key = byId)
print(sorted_vals)