按项对元组列表进行分组

4

我以这个列表作为例子:

[(148, Decimal('3.0')), (325, Decimal('3.0')), (148, Decimal('2.0')), (183, Decimal('1.0')), (308, Decimal('1.0')), (530, Decimal('1.0')), (594, Decimal('1.0')), (686, Decimal('1.0')), (756, Decimal('1.0')), (806, Decimal('1.0'))]

现在我想按id分组,所以我会使用itemgetter(0)

import operator, itertools
from decimal import *
test=[(148, Decimal('3.0')), (325, Decimal('3.0')), (148, Decimal('2.0')), (183, Decimal('1.0')), (308, Decimal('1.0')), (530, Decimal('1.0')), (594, Decimal('1.0')), (686, Decimal('1.0')), (756, Decimal('1.0')), (806, Decimal('1.0'))]

for _k, data in itertools.groupby(test, operator.itemgetter(0)):
    print list(data) 

我不知道为什么我得到了错误的输出:
[(148, Decimal('3.0'))]
[(325, Decimal('3.0'))]
[(148, Decimal('2.0'))]
[(183, Decimal('1.0'))]
[(308, Decimal('1.0'))]
[(530, Decimal('1.0'))]
[(594, Decimal('1.0'))]
[(686, Decimal('1.0'))]
[(756, Decimal('1.0'))]
[(806, Decimal('1.0'))]

正如您所看到的,输出结果并没有按照id进行分组。然而,如果我使用itemgetter(1),上面的代码可以正常工作。输出结果会按照小数值进行分组。

[(148, Decimal('3.0')), (325, Decimal('3.0'))]
[(148, Decimal('2.0'))]
[(183, Decimal('1.0')), (308, Decimal('1.0')), (530, Decimal('1.0')), (594, Decimal('1.0')), (686, Decimal('1.0')), (756, Decimal('1.0')), (806, Decimal('1.0'))]

我在这里缺少什么?
2个回答

4

首先,您需要对数据进行排序,以便groupby可以正常工作,它会根据您提供的键将连续元素分组:

import operator, itertools
from decimal import *
test=[(148, Decimal('3.0')), (325, Decimal('3.0')), (148, Decimal('2.0')), (183, Decimal('1.0')), (308, Decimal('1.0')), (530, Decimal('1.0')), (594, Decimal('1.0')), (686, Decimal('1.0')), (756, Decimal('1.0')), (806, Decimal('1.0'))]

for _k, data in itertools.groupby(sorted(test), operator.itemgetter(0)):
    print list(data)

但是,最好使用dict进行分组,以避免不必要的O(n log n)排序:

from collections import defaultdict

d = defaultdict(list)

for t in test:
    d[t[0]].append(t)

for v in d.values():
    print(v)

两者都会给你相同的分组,只是不一定按照相同的顺序。


2

itertools.groupby()需要数据保持一致或排序。

[(148, Decimal('3.0')), (148, Decimal('2.0')), (325, Decimal('3.0'))]会起作用,但是[(148, Decimal('3.0')), (325, Decimal('3.0')), (148, Decimal('2.0'))]不会起作用,因为id是148、325、148而不是148、148、325


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