将一个字典列表拆分为多个字典列表

24

我已经花了一段时间努力尝试但没有成功...非常感谢任何帮助。

我有:

[{'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},
...]

我想要按照每个事件将字典列表拆分,如下所示(事件数量可以是任意的):

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 = ...
5个回答

28

使用 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

这种方法可以避免对事件的数量或是否有事件缺失进行任何假设。

这会给你一个列表的列表。如果你想要一个以事件为索引的字典,我可能会使用dict(d),如果你计划进行任意随机访问。

至于构建一堆单独的列表,我认为这是个坏主意。它将需要将它们创建为全局变量或使用eval(或以其他方式进行欺骗),除非你确切知道它们将有多少个,否则不要这样做。最好将它们保存在一个容器中。


5

由于排序,这个算法的时间复杂度为 O(n log n),但是除非列表中有很多项目,否则不用太担心。

如果列表已经按事件排序,那么当然可以跳过排序步骤。

>>> 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}]

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

如果您知道您的“事件”键是连续的从零开始的整数,那么您可以使用列表,但是额外的复杂性可能不会带来任何好处。

defaultdict在Python 2.5中添加,但早期版本的解决方法并不难(请参见Nick D的代码)。


1

我认为你真正想要的是筛选它们:

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

这个解决方案不会创建额外的结构。(考虑到大型事件列表的情况)
另一个非常好的解决方案是使用 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}

0
我认为一个简单的实现就足够了。
grouping = {}    
for d in dictlist:
    if d[field] not in grouping:
        grouping[d[field]] = []
    grouping[d[field]].append(d)
result = list(grouping.values())

1
谢谢丹尼尔!最后一行可能应该是:result = grouping.values() - Wim Feijen
谢谢 :) @WimFeijen - Daniel Braun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接