我有一个字典列表,其结构与此类似:
log = [{'user_id': 'id1', 'action': 'action1', 'timestamp': 'time1'},
{'user_id': 'id2', 'action': 'action2', 'timestamp': 'time2'},
...]
并按时间戳值排序。
我想删除由同一用户完成的顺序相同的操作,只留下第一个,例如如果我有以下清单:
log = [{'user_id': 'id1', 'action': 'action1', 'timestamp': 'time1'},
{'user_id': 'id1', 'action': 'action1', 'timestamp': 'time2'},
{'user_id': 'id1', 'action': 'action1', 'timestamp': 'time3'},
{'user_id': 'id2', 'action': 'action2', 'timestamp': 'time4'},
{'user_id': 'id3', 'action': 'action2', 'timestamp': 'time5'},
{'user_id': 'id3', 'action': 'action2', 'timestamp': 'time6'},
{'user_id': 'id1', 'action': 'action1', 'timestamp': 'time7'},
{'user_id': 'id1', 'action': 'action1', 'timestamp': 'time8'}]
我想获得此列表:
log = [{'user_id': 'id1', 'action': 'action1', 'timestamp': 'time1'},
{'user_id': 'id2', 'action': 'action2', 'timestamp': 'time4'},
{'user_id': 'id3', 'action': 'action2', 'timestamp': 'time5'},
{'user_id': 'id1', 'action': 'action1', 'timestamp': 'time7'}]
目前我这样做:
def merge_actions(log):
merged_log = []
merged_log.append(log[0])
for i in range(1, len(log)):
if log[i]['user_id'] == log[i-1]['user_id']:
if log[i]['action'] == log[i-1]['action']:
continue
merged_log.append(log[i])
return merged_log
有更好的方法吗?
答案 0 :(得分:6)
如果您使用itertools.groupby
并按'user_id'
和'action'
分组,则可以抓取每个组中的第一个元素。
>>> [next(group) for key, group in itertools.groupby(log, key = lambda i: (i['user_id'], i['action']))]
[{'timestamp': 'time1', 'action': 'action1', 'user_id': 'id1'},
{'timestamp': 'time4', 'action': 'action2', 'user_id': 'id2'},
{'timestamp': 'time5', 'action': 'action2', 'user_id': 'id3'},
{'timestamp': 'time7', 'action': 'action1', 'user_id': 'id1'}]
答案 1 :(得分:3)
使用itertools.groupby
对同一用户的连续操作进行分组,然后获取每个组的第一个元素:
def merge_actions(log):
return [next(group) for key, group in itertools.groupby(log, lambda l: (l['user_id'], l['action']))
答案 2 :(得分:2)
如果你要使用循环,你只需要跟踪你看到的最后一个键:
it = iter(log)
start = next(it)
od,prev = [start], start["user_id"]
for d in it:
k = d["user_id"]
if prev != k:
od.append(d)
prev = k
print(od)
[{'action': 'action1', 'timestamp': 'time1', 'user_id': 'id1'},
{'action': 'action2', 'timestamp': 'time4', 'user_id': 'id2'},
{'action': 'action2', 'timestamp': 'time5', 'user_id': 'id3'},
{'action': 'action1', 'timestamp': 'time7', 'user_id': 'id1'}]
如果操作并非总是分组,请检查两个键:
it = iter(log)
start = next(it)
od, prev,act = [start], start["user_id"],start["action"]
for d in it:
k1, k2 = d["user_id"], d["action"]
if prev != k1 or k2 != act:
od.append(d)
prev, act = k1, k2
答案 3 :(得分:1)
以下是使用groupby
的详细尝试:
from itertools import groupby
a = [{'user_id': 'id1', 'action': 'action1', 'timestamp': 'time1'},
{'user_id': 'id1', 'action': 'action1', 'timestamp': 'time2'},
{'user_id': 'id1', 'action': 'action1', 'timestamp': 'time3'},
{'user_id': 'id2', 'action': 'action2', 'timestamp': 'time4'},
{'user_id': 'id3', 'action': 'action2', 'timestamp': 'time5'},
{'user_id': 'id3', 'action': 'action2', 'timestamp': 'time6'},
{'user_id': 'id1', 'action': 'action1', 'timestamp': 'time7'},
{'user_id': 'id1', 'action': 'action1', 'timestamp': 'time8'}]
for u, grps in groupby(a, lambda d: d['user_id']):
d_with_first_ts = sorted(grps, key = lambda user_dict: user_dict['timestamp'])[0]
print('User: {}; Dict with first timestamp = {}'.format(u, d_with_first_ts))
您将获得以下结果:
User: id1; Dict with first timestamp = {'timestamp': 'time1', 'action': 'action1', 'user_id': 'id1'}
User: id2; Dict with first timestamp = {'timestamp': 'time4', 'action': 'action2', 'user_id': 'id2'}
User: id3; Dict with first timestamp = {'timestamp': 'time5', 'action': 'action2', 'user_id': 'id3'}
User: id1; Dict with first timestamp = {'timestamp': 'time7', 'action': 'action1', 'user_id': 'id1'}