Python如何将字典列表按UserName分组为嵌套字典结构
问题描述
现有如下字典列表:
[ {'UserName': 'aaa', 'AccessKeyId': 'AKIAYWQTISJD6X27YVK', 'Status': 'Active', 'CreateDate': datetime.datetime(2022, 9, 8, 15, 56, 39, tzinfo=tzutc())}, {'UserName': 'eee', 'AccessKeyId': 'AKIAYWQTISJD6QXMAKY', 'Status': 'Active', 'CreateDate': datetime.datetime(2023, 1, 24, 12, 30, 59, tzinfo=tzutc())}, {'UserName': 'eee', 'AccessKeyId': 'AKIAYWQTISJDUARK6FV', 'Status': 'Active', 'CreateDate': datetime.datetime(2023, 1, 24, 16, 58, 38, tzinfo=tzutc())} ]
需要转换为以UserName为键、对应值为该用户相关字典(移除UserName字段)列表的嵌套字典:
{ "aaa": [ {'AccessKeyId': 'AKIAYWQTISJD6X27YVK', 'Status': 'Active', 'CreateDate': datetime.datetime(2022, 9, 8, 15, 56, 39, tzinfo=tzutc())}], "eee": [ {'AccessKeyId': 'AKIAYWQTISJD6QXMAKY', 'Status': 'Active', 'CreateDate': datetime.datetime(2023, 1, 24, 12, 30, 59, tzinfo=tzutc())}, {'AccessKeyId': 'AKIAYWQTISJDUARK6FV', 'Status': 'Active', 'CreateDate': datetime.datetime(2023, 1, 24, 16, 58, 38, tzinfo=tzutc())} ] }
尝试了以下代码,但同一用户的多条数据仅能保留最后一条,无法生成列表:
import copy list_per_user = {i['UserName']: copy.deepcopy(i) for i in key_list} for obj in list_per_user: del list_per_user[obj]['UserName']
解决方案
问题出在字典推导式的特性:当键重复时,后面的键值对会覆盖前面的,所以同一用户的多条记录最后只留下了最后一条。要实现需求,需要为每个用户维护一个列表,把对应记录添加进去。
方法一:普通循环实现
from datetime import datetime, timezone import copy key_list = [ {'UserName': 'aaa', 'AccessKeyId': 'AKIAYWQTISJD6X27YVK', 'Status': 'Active', 'CreateDate': datetime(2022, 9, 8, 15, 56, 39, tzinfo=timezone.utc)}, {'UserName': 'eee', 'AccessKeyId': 'AKIAYWQTISJD6QXMAKY', 'Status': 'Active', 'CreateDate': datetime(2023, 1, 24, 12, 30, 59, tzinfo=timezone.utc)}, {'UserName': 'eee', 'AccessKeyId': 'AKIAYWQTISJDUARK6FV', 'Status': 'Active', 'CreateDate': datetime(2023, 1, 24, 16, 58, 38, tzinfo=timezone.utc)} ] result = {} for item in key_list: username = item['UserName'] # 深拷贝原字典并移除UserName字段 user_data = copy.deepcopy(item) del user_data['UserName'] # 如果用户已在结果中,追加数据;否则创建新列表 if username in result: result[username].append(user_data) else: result[username] = [user_data] print(result)
方法二:使用collections.defaultdict简化代码
defaultdict可以自动为不存在的键生成默认值(这里是空列表),让代码更简洁:
from datetime import datetime, timezone import copy from collections import defaultdict key_list = [ {'UserName': 'aaa', 'AccessKeyId': 'AKIAYWQTISJD6X27YVK', 'Status': 'Active', 'CreateDate': datetime(2022, 9, 8, 15, 56, 39, tzinfo=timezone.utc)}, {'UserName': 'eee', 'AccessKeyId': 'AKIAYWQTISJD6QXMAKY', 'Status': 'Active', 'CreateDate': datetime(2023, 1, 24, 12, 30, 59, tzinfo=timezone.utc)}, {'UserName': 'eee', 'AccessKeyId': 'AKIAYWQTISJDUARK6FV', 'Status': 'Active', 'CreateDate': datetime(2023, 1, 24, 16, 58, 38, tzinfo=timezone.utc)} ] result = defaultdict(list) for item in key_list: user_data = copy.deepcopy(item) del user_data['UserName'] result[item['UserName']].append(user_data) # 如果需要转为普通字典,可执行:result = dict(result) print(result)
方法三:不使用深拷贝(如果原数据不需要保留)
如果不需要保留原列表中的字典,可以直接修改原字典(注意这会改变原数据),省去深拷贝的开销:
from datetime import datetime, timezone from collections import defaultdict key_list = [ {'UserName': 'aaa', 'AccessKeyId': 'AKIAYWQTISJD6X27YVK', 'Status': 'Active', 'CreateDate': datetime(2022, 9, 8, 15, 56, 39, tzinfo=timezone.utc)}, {'UserName': 'eee', 'AccessKeyId': 'AKIAYWQTISJD6QXMAKY', 'Status': 'Active', 'CreateDate': datetime(2023, 1, 24, 12, 30, 59, tzinfo=timezone.utc)}, {'UserName': 'eee', 'AccessKeyId': 'AKIAYWQTISJDUARK6FV', 'Status': 'Active', 'CreateDate': datetime(2023, 1, 24, 16, 58, 38, tzinfo=timezone.utc)} ] result = defaultdict(list) for item in key_list: username = item.pop('UserName') result[username].append(item) print(result)
内容的提问来源于stack exchange,提问作者opti2k4
相关产品推荐
相关产品推荐

