24

I've been whacking away at this for a while to no avail... Any help would be greatly appreciated.

I have:

[{'event': 0, 'voltage': 1, 'time': 0},
{'event': 0, 'voltage': 2, 'time': 1},
{'event': 1, 'voltage': 1, 'time': 2},
{'event': 1, 'voltage': 2, 'time': 3},
{'event': 2, 'voltage': 1, 'time': 4},
{'event': 2, 'voltage': 2, 'time': 5},
...]

and I want to split that list of dictionaries up per event like this (there can be arbitrarily many events):

list0 = [{'event': 0, 'voltage': 1, 'time': 0},
{'event': 0, 'voltage': 2, 'time': 1}]

list1 = [{'event': 1, 'voltage': 1, 'time': 2},
{'event': 1, 'voltage': 2, 'time': 3}]

list2 = [{'event': 2, 'voltage': 1, 'time': 4},
{'event': 2, 'voltage': 2, 'time': 5}]

listN = ...
thenickname
  • 6,684
  • 14
  • 41
  • 42

5 Answers5

28

use defaultdict

import collections

result = collections.defaultdict(list)

for d in dict_list:
    result[d['event']].append(d)

result_list = result.values()        # Python 2.x
result_list = list(result.values())  # Python 3

This way, you don't have to make any assumptions about how many different events there are or if there are any events missing.

This gives you a list of lists. If you want a dict indexed by event, I would probably use dict(d) if you plan on doing any random access.

As far as constructing a bunch of individual lists, I think that that's a bad idea. It will necessitate creating them as globals or using eval (or getting hacky in some other way) unless you know exactly how many there are going to be which you claim not to. It's best to just keep them in a container.

jpp
  • 159,742
  • 34
  • 281
  • 339
aaronasterling
  • 68,820
  • 20
  • 127
  • 125
5

This one is O(n log n) because of the sort, but I wouldn't worry too much unless there are a lot of items in the list.

It the list is already sorted by event, you can skip the sort of course.

>>> from operator import itemgetter
>>> from itertools import groupby
>>> d=[{'event': 0, 'voltage': 1, 'time': 0},
... {'event': 0, 'voltage': 2, 'time': 1},
... {'event': 1, 'voltage': 1, 'time': 2},
... {'event': 1, 'voltage': 2, 'time': 3},
... {'event': 2, 'voltage': 1, 'time': 4},
... {'event': 2, 'voltage': 2, 'time': 5}]
>>> groupby(sorted(d, key=itemgetter('event')), key=itemgetter('event'))
<itertools.groupby object at 0xb78138c4>
>>> for x in _:
...   print x[0], list(x[1])
... 
0 [{'time': 0, 'event': 0, 'voltage': 1}, {'time': 1, 'event': 0, 'voltage': 2}]
1 [{'time': 2, 'event': 1, 'voltage': 1}, {'time': 3, 'event': 1, 'voltage': 2}]
2 [{'time': 4, 'event': 2, 'voltage': 1}, {'time': 5, 'event': 2, 'voltage': 2}]
oz123
  • 27,559
  • 27
  • 125
  • 187
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
1
dict_list = [{'event': 0, 'voltage': 1, 'time': 0},
{'event': 0, 'voltage': 2, 'time': 1},
{'event': 1, 'voltage': 1, 'time': 2},
{'event': 1, 'voltage': 2, 'time': 3},
{'event': 2, 'voltage': 1, 'time': 4},
{'event': 2, 'voltage': 2, 'time': 5},
]

import collections
dol = collections.defaultdict(list)
for d in dict_list:
   k = d["event"]
   dol[k].append(d)

print dol

if you know that your "event" keys are consecutive zero-based integers, you can use a list instead, but the extra complexity may not gain you anything.

defaultdict was added in python 2.5, but the workaround for earlier versions is not hard (see Nick D's code).

Terrel Shumway
  • 454
  • 3
  • 6
1

I think what you really want is to filter them:

elist = [{'event': 0, 'voltage': 1, 'time': 0},
{'event': 0, 'voltage': 2, 'time': 1},
{'event': 1, 'voltage': 1, 'time': 2},
{'event': 1, 'voltage': 2, 'time': 3},
{'event': 2, 'voltage': 1, 'time': 4},
{'event': 2, 'voltage': 2, 'time': 5}]


from itertools import ifilter

def get_events(elist, n):
    return ifilter( lambda d: d['event'] == n , elist)

for e in get_events(elist,0):
    print e

this solution will not create additional structures. (think in case of HUGE event list)

Another very nice solution is to use groupby:

from itertools import groupby
from operator import itemgetter
for group in groupby(elist, itemgetter('event')):
    id, event_list = group
    for e in event_list:
        print e

{'time': 0, 'event': 0, 'voltage': 1}
{'time': 1, 'event': 0, 'voltage': 2}
{'time': 2, 'event': 1, 'voltage': 1}
{'time': 3, 'event': 1, 'voltage': 2}
{'time': 4, 'event': 2, 'voltage': 1}
{'time': 5, 'event': 2, 'voltage': 2}
fabrizioM
  • 46,639
  • 15
  • 102
  • 119
0

A simple implementation will suffice in my opinion:

grouping = {}    
for d in dictlist:
    if d[field] not in grouping:
        grouping[d[field]] = []
    grouping[d[field]].append(d)
result = list(grouping.values())
Daniel Braun
  • 2,452
  • 27
  • 25