我有一份字典清单,如下所示:
[{'user': '123456', 'db': 'db1', 'size': '8628'}
{'user': '123456', 'db': 'db1', 'size': '7168'}
{'user': '123456', 'db': 'db1', 'size': '38160'}
{'user': '222345', 'db': 'db3', 'size': '8628'}
{'user': '222345', 'db': 'db3', 'size': '8628'}
{'user': '222345', 'db': 'db5', 'size': '840'}
{'user': '34521', 'db': 'db6', 'size': '12288'}
{'user': '34521', 'db': 'db6', 'size': '476'}
{'user': '2345156', 'db': 'db7', 'size': '5120'}.....]此列表包含数百万项。每个用户可以在多个dbs中找到,每个用户可以在同一个db中拥有多个实体。我想总结一下每个用户占用多少数据,每分贝。我不想用熊猫。现在我这样做:
。
result = []
for user in unique_users:
for db in unique_dbs:
total_size = 0
for i in big_list:
if (i['user'] == user and i['db'] == db):
total_size += float(i['size'])
if(total_size) > 0:
row = {}
row['user'] = user
row['db'] = db
row['size'] = total_size
result.append(row)问题是,这个三重for循环发展成非常大的东西(数千亿次迭代),需要花费很长时间来总结结果。如果big_list是小的,这是非常好的工作。
为了保持快速和简单,我应该如何处理这个问题?非常感谢!
发布于 2022-10-11 08:51:28
目前的方法主要存在两个问题:低效算法和低效数据结构。
首先,使用的算法显然效率很低,因为它在大列表上多次迭代。不需要对整个列表进行迭代以筛选唯一的用户和db。您可以迭代大列表一次,并使用字典聚合数据。目标字典的键只是一个(user, db)元组。字典的值是total_size。下面是一个未经测试的示例:
# Aggregation part
# Note: a default dict can be used instead to make the code possibly simpler
aggregate_dict = dict()
for i in big_list:
key = (i['user'], i['db'])
value = float(i['size'])
if key in aggregate_dict:
aggregate_dict[key] += value
else:
aggregate_dict[key] = value
# Fast creation of `result`
result = []
for user in unique_users:
for db in unique_dbs:
total_size = aggregate_dict.get((user, key))
if total_size is not None and total_size > 0:
result.append({'user': user, 'db': db, 'size': total_size})另一个问题是低效的数据结构:对于每一行,键被复制,而元组可以被替代。实际上,更好的数据结构是存储(column, items)键值字典,其中items是目标列的项列表。这种存储数据的方式被称为数据。这大概是Pandas内部使用的(除了它是一个Numpy数组,它甚至更好,因为它比大多数操作的列表更紧凑和效率更高)。对于输入和输出都使用这种数据结构将导致显着的加速(如果与Numpy相结合)和一个更低的内存占用。
发布于 2022-10-11 08:47:04
尝试将用户映射到数据库到字典中的总大小。它需要额外的内存,但是访问速度应该更快&只需要通过一次数据:
user_to_db_to_size = {}
for entry in unique_users:
user = entry['user']
db = entry['db']
size = int(entry['size'])
if user not in user_to_db_to_size:
user_to_db_to_size[user] = {}
if db not in user_to_db_to_size[user]:
user_to_db_to_size[user][db] = 0
user_to_db_to_size[user][db] += size
print(user_to_db_to_size)对于您的示例数据,它生成:
{'123456': {'db1': 53956}, '222345': {'db3': 17256, 'db5': 840}, '34521': {'db6': 12764}, '2345156': {'db7': 5120}}现在,您可以使用以下方法访问每个用户/db的总大小:
print(user_to_db_to_size['123456']['db1']) # 53956发布于 2022-10-12 04:39:53
如果您使用计数器并将值对的元组(user,db)作为键,那么:
from collections import Counter
data = [{'user': '123456', 'db': 'db1', 'size': '8628'},
{'user': '123456', 'db': 'db1', 'size': '7168'},
{'user': '123456', 'db': 'db1', 'size': '38160'},
{'user': '222345', 'db': 'db3', 'size': '8628'},
{'user': '222345', 'db': 'db3', 'size': '8628'},
{'user': '222345', 'db': 'db5', 'size': '840'},
{'user': '34521', 'db': 'db6', 'size': '12288'},
{'user': '34521', 'db': 'db6', 'size': '476'},
{'user': '2345156', 'db': 'db7', 'size': '5120'}]
print(sum((Counter({(d['user'], d['db']): int(d['size'])}) for d in data), start=Counter()))
Counter({('123456', 'db1'): 53956, ('222345', 'db3'): 17256, ('34521', 'db6'): 12764, ('2345156', 'db7'): 5120, ('222345', 'db5'): 840})https://stackoverflow.com/questions/74025103
复制相似问题