我想从字典列表生成一个字典,按一些键的值对列表项进行分组,例如:
input_list = [
{'a':'tata', 'b': 'foo'},
{'a':'pipo', 'b': 'titi'},
{'a':'pipo', 'b': 'toto'},
{'a':'tata', 'b': 'bar'}
]
output_dict = {
'pipo': [
{'a': 'pipo', 'b': 'titi'},
{'a': 'pipo', 'b': 'toto'}
],
'tata': [
{'a': 'tata', 'b': 'foo'},
{'a': 'tata', 'b': 'bar'}
]
}
到目前为止,我发现了两种方法。第一个简单地迭代列表,在dict中为每个键值创建子列表,并将匹配这些键的元素附加到子列表:
l = [
{'a':'tata', 'b': 'foo'},
{'a':'pipo', 'b': 'titi'},
{'a':'pipo', 'b': 'toto'},
{'a':'tata', 'b': 'bar'}
]
res = {}
for e in l:
res[e['a']] = res.get(e['a'], [])
res[e['a']].append(e)
另一个使用itertools.groupby
:
import itertools
from operator import itemgetter
l = [
{'a':'tata', 'b': 'foo'},
{'a':'pipo', 'b': 'titi'},
{'a':'pipo', 'b': 'toto'},
{'a':'tata', 'b': 'bar'}
]
l = sorted(l, key=itemgetter('a'))
res = dict((k, list(g)) for k, g in itertools.groupby(l, key=itemgetter('a')))
我想知道哪种方案效率最高?
还有更多的pythonic /简洁或更好的实现方法吗?
答案 0 :(得分:12)
您是否希望按列表元素的“a”键的值对输入列表进行分组?如果是这样,您的第一种方法是最好的,一次小的改进,使用dict.setdefault
:
res = {}
for item in l:
res.setdefault(item['a'], []).append(item)
答案 1 :(得分:5)
一个班轮 -
>>> import itertools
>>> input_list = [
... {'a':'tata', 'b': 'foo'},
... {'a':'pipo', 'b': 'titi'},
... {'a':'pipo', 'b': 'toto'},
... {'a':'tata', 'b': 'bar'}
... ]
>>> {k:[v for v in input_list if v['a'] == k] for k, val in itertools.groupby(input_list,lambda x: x['a'])}
{'tata': [{'a': 'tata', 'b': 'foo'}, {'a': 'tata', 'b': 'bar'}], 'pipo': [{'a': 'pipo', 'b': 'titi'}, {'a': 'pipo', 'b': 'toto'}]}
答案 2 :(得分:3)
如果有效表示"时间效率高,,则可以使用timeit
内置模块对其进行衡量。< / p>
例如:
import timeit
import itertools
from operator import itemgetter
input = [{'a': 'tata', 'b': 'foo'},
{'a': 'pipo', 'b': 'titi'},
{'a': 'pipo', 'b': 'toto'},
{'a': 'tata', 'b': 'bar'}]
def solution1():
res = {}
for e in input:
res[e['a']] = res.get(e['a'], [])
res[e['a']].append(e)
return res
def solution2():
l = sorted(input, key=itemgetter('a'))
res = dict(
(k, list(g)) for k, g in itertools.groupby(l, key=itemgetter('a'))
)
return res
t = timeit.Timer(solution1)
print(t.timeit(10000))
# 0.0122511386871
t = timeit.Timer(solution2)
print(t.timeit(10000))
# 0.0366218090057
有关详细信息,请参阅timeit official docs。
答案 3 :(得分:1)
最好的方法是你提到的第一个方法,你甚至可以使用bernhard上面提到的setdefault
来使它更优雅。这种方法的复杂性是O(n),因为我们只是迭代输入一次,对于每个项目,我们执行查找到我们正在构建的输出字典,以找到适当的列表来附加它,这需要恒定的时间(查找+追加)每个项目。因此,重叠的复杂性是O(n),这是最佳的。
使用itertools.groupby时,必须事先对输入进行排序(即O(n log n))。