Python:将dict中的列表项分组

Python:将dict中的列表项分组,python,algorithm,dictionary,group-by,Python,Algorithm,Dictionary,Group By,我想从字典列表中生成一个字典,根据某个键的值对列表项进行分组,例如: 输入列表=[ {'a':'tata','b':'foo'}, {'a':'pipo','b':'titi'}, {'a':'pipo','b':'toto'}, {'a':'tata','b':'bar'} ] 输出指令={ “皮波”:[ {'a':'pipo','b':'titi'}, {'a':'pipo','b':'toto'} ], “塔塔”:[ {'a':'tata','b':'foo'}, {'a':'tata',

我想从字典列表中生成一个字典,根据某个键的值对列表项进行分组,例如:

输入列表=[
{'a':'tata','b':'foo'},
{'a':'pipo','b':'titi'},
{'a':'pipo','b':'toto'},
{'a':'tata','b':'bar'}
]
输出指令={
“皮波”:[
{'a':'pipo','b':'titi'},
{'a':'pipo','b':'toto'}
],
“塔塔”:[
{'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')))
我想知道哪种选择最有效


有没有比这更具python风格的/简洁的或性能更好的方法呢?

您是否希望按列表元素的“a”键的值对输入列表进行分组?如果是这样的话,您的第一种方法是最好的,一个小小的改进,使用:

一艘班轮-

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

最好的方法是您提到的第一种方法,您甚至可以使用上面bernhard提到的方法使其更加优雅。这种方法的复杂性是O(n),因为我们只需对输入进行一次迭代,对于我们正在构建的输出dict中的每个项,我们执行一次查找,以找到要将其附加到的适当列表,这对每个项来说都需要恒定的时间(查找+附加)。所以覆盖复杂度是O(n),这是最优的


使用itertools.groupby时,必须事先对输入进行排序(即O(n log n))

如果所说的高效是指“高效时间”,则可以使用
timeit
内置模块对其进行测量

例如:

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

请参阅以获取更多信息。

(是的,我“希望根据列表元素的“a”键的值对输入列表进行分组”是正确的,
groupby
似乎是最好的选择,但是我担心与简单的
for
循环相比,之前的强制排序会增加不必要的复杂性)“best”指的是复杂性,是的。我觉得我的问题措词不当。我将接受你的答案,因为这是投票最多的答案,并且实际上回答了我的问题。然而,@gen-y-s的答案也很好,因为它澄清了问题和原因,另一个证明了它的时间效率,这在某些情况下可能与竞争性不同:例如,如果输入数据集基本上是有序的——这是我的真实数据——第二种方法的复杂性仍然是O(n)。还请注意,@ewilazarus answer实际上表明,相对于我几乎排序的数据,您的解决方案更有效。我已经知道第二种方法的复杂性是O(n log n),因此更糟,但感谢您澄清这一点。我实际上在寻找一个与方法1具有相同复杂性的解决方案,但使用了一个低开销、内存效率高、高性能等的解决方案,如
itertools
中的解决方案。我想在这种情况下是没有的。还要注意python使用了timsort,它在大量排序的数据上具有O(n)复杂性:是的,我实际上是指时间效率。谢谢分享。
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