在Python中过滤字典列表的更好方法

yan*_*ana 3 python python-2.7

我有一个字典列表,其结构与此类似:

log = [{'user_id': 'id1', 'action': 'action1', 'timestamp': 'time1'},  
       {'user_id': 'id2', 'action': 'action2', 'timestamp': 'time2'},
       ...]
Run Code Online (Sandbox Code Playgroud)

并按时间戳值排序.

我想删除由同一个用户完成的顺序相同的操作,只留下第一个,例如,如果我有以下列表:

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'}]
Run Code Online (Sandbox Code Playgroud)

我希望得到这个列表:

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'}]
Run Code Online (Sandbox Code Playgroud)

目前我这样做:

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
Run Code Online (Sandbox Code Playgroud)

有一个更好的方法吗?

Cor*_*mer 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'}]
Run Code Online (Sandbox Code Playgroud)

  • `key = itemgetter('user_id','action')`将完成同样的工作而不需要lambda (2认同)