2014-09-17 4 views
2

Я пытаюсь превратить это:Group список dicts два значений в питоне

[ 
    {'perm':'copy', 'id':1, 'name':'user1'}, 
    {'perm':'read', 'id':1, 'name':'user1'}, 
    {'perm':'delete', 'id':2, 'name':'user2'}, 
    {'perm':'copy', 'id':2, 'name':'user2'}, 
    {'perm':'update', 'id':3, 'name':'user3'} 
] 

в этом:

[ 
    {'id':1, 'name':'user1', 'perms': {'copy': True, 'read': True}} 
    {'id':2, 'name':'user2', 'perms': {'copy': True, 'delete': True}} 
    {'id':3, 'name':'user3', 'perms': {'update': True }} 
] 

Что такое лучший «вещий» способ сделать это ?

itertools.groupby выглядит как беспорядок, и я не хочу загружать такие тяжелые пакеты, как панды, для чего-то подобного.

ответ

5

Вы должны использовать только itertools.groupby, если ваш список ввода всегда отсортирован; в вашем примере ввода списка это так, чтобы вы могли сделать:

from operator import itemgetter 
from itertools import groupby 

[{'perms': dict.fromkeys((p['perm'] for p in group), True), 'id': key[0], 'user': key[1]} 
for key, group in groupby(inputlist, itemgetter('id', 'name'))] 

Альтернативный маршрут, чтобы использовать словарь, чтобы собрать разрешения для каждого пользователя, а затем производит список из этого словаря:

per_user = {} 

for perm in inputlist: 
    key = perm['id'], perm['name'] 
    per_user.setdefault(key, {})[perm['perm']] = True 

[{'perms': value, 'id': key[0], 'user': key[1]} for key, value in per_user.iteritems()] 

Демо:

>>> from operator import itemgetter 
>>> from itertools import groupby 
>>> from pprint import pprint 
>>> inputlist = [ 
... {'perm':'copy', 'id':1, 'name':'user1'}, 
... {'perm':'read', 'id':1, 'name':'user1'}, 
... {'perm':'delete', 'id':2, 'name':'user2'}, 
... {'perm':'copy', 'id':2, 'name':'user2'}, 
... {'perm':'update', 'id':3, 'name':'user3'} 
... ] 
>>> [{'perms': dict.fromkeys((p['perm'] for p in group), True), 'id': key[0], 'user': key[1]} 
... for key, group in groupby(inputlist, itemgetter('id', 'name'))] 
[{'perms': {'read': True, 'copy': True}, 'id': 1, 'user': 'user1'}, {'perms': {'copy': True, 'delete': True}, 'id': 2, 'user': 'user2'}, {'perms': {'update': True}, 'id': 3, 'user': 'user3'}] 
>>> pprint(_) 
[{'id': 1, 'perms': {'copy': True, 'read': True}, 'user': 'user1'}, 
{'id': 2, 'perms': {'copy': True, 'delete': True}, 'user': 'user2'}, 
{'id': 3, 'perms': {'update': True}, 'user': 'user3'}] 
>>> per_user = {} 
>>> for perm in inputlist: 
...  key = perm['id'], perm['name'] 
...  per_user.setdefault(key, {})[perm['perm']] = True 
... 
>>> [{'perms': value, 'id': key[0], 'user': key[1]} for key, value in per_user.iteritems()] 
[{'perms': {'update': True}, 'id': 3, 'user': 'user3'}, {'perms': {'copy': True, 'delete': True}, 'id': 2, 'user': 'user2'}, {'perms': {'read': True, 'copy': True}, 'id': 1, 'user': 'user1'}] 
>>> pprint(_) 
[{'id': 3, 'perms': {'update': True}, 'user': 'user3'}, 
{'id': 2, 'perms': {'copy': True, 'delete': True}, 'user': 'user2'}, 
{'id': 1, 'perms': {'copy': True, 'read': True}, 'user': 'user1'}] 
+0

Спасибо, Ваш хватает скобки в первом примере. Кроме того, идентификатор отсутствует. – haki

+0

Построенный на вас ответ, но заменивший itemgetter лямбдой, чтобы получить оба значения, дал мне результат, который я искал. '[{'perms': dict.fromkeys ((p ['perm'] для p в группе), True), 'user': key [0], 'id': key [1]} для клавиши, group in groupby (inputlist, lambda t: (t ['name'], t ['id']))] ' – haki

+0

@haki: ах, я пропустил недостающий идентификатор, исправлен. –

Смежные вопросы