我有三个dict列表,一些示例数据看起来像:
list_1.append({"shared_id": "111", "users": [{"id": "444", "opens": 2}, {"id": "555", "opens": 2}]})
list_1.append({"shared_id": "222", "users": [{"id": "444", "opens": 2}, {"id": "555", "opens": 3}]})
list_2.append({"shared_id": "111", "users": [{"id": "444", "clicks": 1}, {"id": "555", "clicks": 2}]})
list_2.append({"shared_id": "222", "users": [{"id": "444", "clicks": 3}, {"id": "555", "clicks": 3}]})
list_3.append({"shared_id": "111", "users": [{"id": "444", "bounces": 2}, {"id": "555", "bounces": 1}]})
list_3.append({"shared_id": "222", "users": [{"id": "444", "bounces": 3}, {"id": "555", "bounces": 2}]})
使用我想创建1个看起来像以下内容的用户上的共享ID和ID,看起来像:
combined_list.append([{"shared_id": "111", "users": [{"id": "444", "opens": 2, "clicks": 1, "bounces": 2, "combined_id": 444111}, {"id": "555", "opens": 3, "clicks": 2, "bounces": 1, "combined_id": 555111}}])
combined_list.append([{"shared_id": "222", "users": [{"id": "444", "opens": 2, "clicks": 3, "bounces": 1, "combined_id": 444222}, {"id": "555", "opens": 3, "clicks": 3, "bounces": 2, "combined_id": 555222}}])
当我使用嵌套循环的2个列表时,我已经解决了它,但是代码超级凌乱,感觉不太好,现在我正在使用3个列表,现在有更好的方法吗?
for o in list_1:
for c in list_2:
if o['shared_id'] == c['shared_id']:
csd = {
'users': [],
'shared_id': o['shared_id']
}
for op in o['users']:
for cp in c['users']:
if op['id'] == cp['id']:
cpd = {
'opens': op['opens'],
'clicks': cp['clicks'],
'combined_id': '{}{}'.format(
op['id'],
csd['shared_id']
)
}
csd['users'].append(cpd)
combined.append(csd)
在这里为此一个简单的功能:
from pprint import pprint
def combine_lists(*lists):
result = {}
# For each list
for lst in lists:
# For each dict in the list
for d1 in lst:
# Get or make common dict for shared_id
shared_id = d1["shared_id"]
shared_dict = result.setdefault(shared_id, {})
# For each user dict in the dict
for d2 in d1["users"]:
# Get or make user dict
user_id = d2["id"]
if user_id not in shared_dict:
shared_dict[user_id] = {"combined_id": "{}{}".format(user_id, shared_id)}
# Update information in user dictionary
shared_dict[user_id].update(d2)
# Make output as a list
return [{"shared_id": k, "users": list(v.values())} for k, v in result.items()]
# Test
list_1 = []
list_1.append({"shared_id": "111", "users": [{"id": "444", "opens": 2}, {"id": "555", "opens": 2}]})
list_1.append({"shared_id": "222", "users": [{"id": "444", "opens": 2}, {"id": "555", "opens": 3}]})
list_2 = []
list_2.append({"shared_id": "111", "users": [{"id": "444", "clicks": 1}, {"id": "555", "clicks": 2}]})
list_2.append({"shared_id": "222", "users": [{"id": "444", "clicks": 3}, {"id": "555", "clicks": 3}]})
list_3 = []
list_3.append({"shared_id": "111", "users": [{"id": "444", "bounces": 2}, {"id": "555", "bounces": 1}]})
list_3.append({"shared_id": "222", "users": [{"id": "444", "bounces": 3}, {"id": "555", "bounces": 2}]})
pprint(combine_lists(list_1, list_2, list_3))
# [{'shared_id': '111',
# 'users': [{'bounces': 2,
# 'clicks': 1,
# 'combined_id': '444111',
# 'id': '444',
# 'opens': 2},
# {'bounces': 1,
# 'clicks': 2,
# 'combined_id': '555111',
# 'id': '555',
# 'opens': 2}]},
# {'shared_id': '222',
# 'users': [{'bounces': 3,
# 'clicks': 3,
# 'combined_id': '444222',
# 'id': '444',
# 'opens': 2},
# {'bounces': 2,
# 'clicks': 3,
# 'combined_id': '555222',
# 'id': '555',
# 'opens': 3}]}]
您可以使用 itertools.groupby
(doc(进行分组元素:
list_1, list_2, list_3 = [], [], []
list_1.append({"shared_id": "111", "users": [{"id": "444", "opens": 2}, {"id": "555", "opens": 2}]})
list_1.append({"shared_id": "222", "users": [{"id": "444", "opens": 2}, {"id": "555", "opens": 3}]})
list_2.append({"shared_id": "111", "users": [{"id": "444", "clicks": 1}, {"id": "555", "clicks": 2}]})
list_2.append({"shared_id": "222", "users": [{"id": "444", "clicks": 3}, {"id": "555", "clicks": 3}]})
list_3.append({"shared_id": "111", "users": [{"id": "444", "bounces": 2}, {"id": "555", "bounces": 1}]})
list_3.append({"shared_id": "222", "users": [{"id": "444", "bounces": 3}, {"id": "555", "bounces": 2}]})
from itertools import groupby
shared_ids = {}
for v, g in groupby(sorted(list_1 + list_2 + list_3, key=lambda k: k['shared_id']), lambda k: k['shared_id']):
for shared_id in g:
for user in shared_id['users']:
shared_ids.setdefault(v, {}).setdefault(user['id'], {}).update(**user)
shared_ids[v][user['id']]['combined_id'] = '{}{}'.format(user['id'], v)
out = [{'shared_id': k, 'users': [shared_ids[k][kk] for kk in shared_ids[k]]} for k in shared_ids]
from pprint import pprint
pprint(out)
打印:
[{'shared_id': '111',
'users': [{'bounces': 2, 'clicks': 1, 'combined_id': '444111', 'id': '444', 'opens': 2},
{'bounces': 1, 'clicks': 2, 'combined_id': '555111', 'id': '555', 'opens': 2}]},
{'shared_id': '222',
'users': [{'bounces': 3, 'clicks': 3, 'combined_id': '444222', 'id': '444', 'opens': 2},
{'bounces': 2, 'clicks': 3, 'combined_id': '555222', 'id': '555', 'opens': 3}]}]
注意:如果打印shared_ids
变量,则获得:
{'111': {'444': {'bounces': 2, 'clicks': 1, 'combined_id': '444111', 'id': '444', 'opens': 2},
'555': {'bounces': 1, 'clicks': 2, 'combined_id': '555111', 'id': '555', 'opens': 2}},
'222': {'444': {'bounces': 3, 'clicks': 3, 'combined_id': '444222', 'id': '444', 'opens': 2},
'555': {'bounces': 2, 'clicks': 3, 'combined_id': '555222', 'id': '555', 'opens': 3}}}
也许这个词典会更好地操纵。
反对方向的解决方案
# Data structure to manage shared object information
class shared(object):
def __init__(self, i):
self.i = i
self.users = dict()
# Add information of the particulate user
def update_user(self, user_id, key, value):
if user_id in self.users:
self.users[user_id][key] = value
else:
self.users[user_id]= {key:value,
"id":user_id,
"combined_id": "{0}{1}".format(user_id,self.i)}
# Return the information is required format
def get(self):
return {
'shared_id': self.i,
'users' : [ user for user in self.users.values()]
}
数据
list_1 = []
list_2 = []
list_3 = []
list_1.append({"shared_id": "111", "users": [{"id": "444", "opens": 2}, {"id": "555", "opens": 2}]})
list_1.append({"shared_id": "222", "users": [{"id": "444", "opens": 2}, {"id": "555", "opens": 3}]})
list_2.append({"shared_id": "111", "users": [{"id": "444", "clicks": 1}, {"id": "555", "clicks": 2}]})
list_2.append({"shared_id": "222", "users": [{"id": "444", "clicks": 3}, {"id": "555", "clicks": 3}]})
list_3.append({"shared_id": "111", "users": [{"id": "444", "bounces": 2}, {"id": "555", "bounces": 1}]})
list_3.append({"shared_id": "222", "users": [{"id": "444", "bounces": 3}, {"id": "555", "bounces": 2}]})
解析数据
info = {}
for l in list_1+list_2+list_3:
# Is there already information for this shared_id ?
if l["shared_id"] not in info:
info[l["shared_id"]] = shared(l["shared_id"])
# Parse all the users
for user_info in l['users']:
user_id = user_info["id"]
# Parse the user information
for key,value in user_info.items():
if key != "id":
# Update the user information
info[l["shared_id"]].update_user(user_id, key, value)
result = [x.get() for x in info.values()]
print (result)
输出
[{'shared_id': '111', 'users': [{'opens': 2, 'id': '444', 'combined_id': '444111', 'clicks': 1, 'bounces': 2}, {'opens': 2, 'id': '555', 'combined_id': '555111', 'clicks': 2, 'bounces': 1}]},
{'shared_id': '222', 'users': [{'opens': 2, 'id': '444', 'combined_id': '444222', 'clicks': 3, 'bounces': 3}, {'opens': 3, 'id': '555', 'combined_id': '555222', 'clicks': 3, 'bounces': 2}]}]
您可以使用itertools.groupby()
将ID分组在一起,然后根据需要合并字典:
from collections import ChainMap
from itertools import chain, groupby
from operator import itemgetter
combined_list = []
for k, g in groupby(sorted(chain(list_1, list_2, list_3), key=itemgetter('shared_id')), key=itemgetter('shared_id')):
users = []
for k2, g2 in groupby(sorted(chain(*map(itemgetter('users'), g)), key=itemgetter('id')), key=itemgetter('id')):
users.append({'id': k2, 'combined_id': k2 + k, **ChainMap(*g2)})
combined_list.append({'shared_id': k, 'users': users})
print(combined_list)
输出:
[{'shared_id': '111', 'users': [{'id': '444', 'combined_id': '444111', 'bounces': 2, 'clicks': 1, 'opens': 2}, {'id': '555', 'combined_id': '555111', 'bounces': 1, 'clicks': 2, 'opens': 2}]}, {'shared_id': '222', 'users': [{'id': '444', 'combined_id': '444222', 'bounces': 3, 'clicks': 3, 'opens': 2}, {'id': '555', 'combined_id': '555222', 'bounces': 2, 'clicks': 3, 'opens': 3}]}]
global_list = []
def add_item(item):
item_found = False
for e_item in global_list:
if e_item['shared_id'] == item['shared_id']:
item_found = True
e_users = e_item['users']
users = item['users']
for user in users:
user_found = False
for e_user in e_users:
if e_user['id'] == user['id']:
user_found = True
e_user.update(user)
if user_found is False:
e_users.append(user)
if item_found is False:
global_list.append(item)
list_1 = []
list_2 = []
list_3 = []
list_1.append({"shared_id": "111", "users": [{"id": "444", "opens": 2}, {"id": "555", "opens": 2}]})
list_1.append({"shared_id": "222", "users": [{"id": "444", "opens": 2}, {"id": "555", "opens": 3}]})
list_2.append({"shared_id": "111", "users": [{"id": "444", "clicks": 1}, {"id": "555", "clicks": 2}]})
list_2.append({"shared_id": "222", "users": [{"id": "444", "clicks": 3}, {"id": "555", "clicks": 3}]})
list_3.append({"shared_id": "111", "users": [{"id": "444", "bounces": 2}, {"id": "555", "bounces": 1}]})
list_3.append({"shared_id": "222", "users": [{"id": "444", "bounces": 3}, {"id": "555", "bounces": 2}]})
for item in list_1+list_2+list_3:
add_item(item)
print(global_list)