itertools.groupby () неправильно группирует - PullRequest
10 голосов
/ 14 ноября 2011

У меня есть эти данные:

self.data = [(1, 1, 5.0),
             (1, 2, 3.0),
             (1, 3, 4.0),
             (2, 1, 4.0),
             (2, 2, 2.0)]

Когда я запускаю этот код:

for mid, group in itertools.groupby(self.data, key=operator.itemgetter(0)):

для list(group) Я получаю:

[(1, 1, 5.0),
 (1, 2, 3.0),
 (1, 3, 4.0)]

что я и хочу.

Но если я использую 1 вместо 0

for mid, group in itertools.groupby(self.data, key=operator.itemgetter(1)):

для группировки по второму номеру в кортежах я получаю только:

[(1, 1, 5.0)]

даже при том, что есть другие кортежи, которые имеют «1» в этой 1 (второй) позиции

Ответы [ 3 ]

22 голосов
/ 14 ноября 2011

itertools.groupby собирает вместе смежные предметы с одинаковым ключом. Если вы хотите, чтобы все элементы имели одинаковый ключ, сначала нужно отсортировать self.data.

for mid, group in itertools.groupby(
    sorted(self.data,key=operator.itemgetter(1)), key=operator.itemgetter(1)):
19 голосов
/ 06 марта 2013

Вариант без сортировки (через словарь). Должно быть лучше с точки зрения производительности.

def full_group_by(l, key=lambda x: x):
    d = defaultdict(list)
    for item in l:
        d[key(item)].append(item)
    return d.items()
2 голосов
/ 10 января 2019

Ниже "исправляет" несколько неприятностей с itertools.groupby в Python.

def groupby2(l, key=lambda x:x, val=lambda x:x, agg=lambda x:x, sort=True):
    if sort:
        l = sorted(l, key=key)
    return ((k, agg((val(x) for x in v))) \
        for k,v in itertools.groupby(l, key=key))

В частности,

  1. Не требуется сортировать данные.
  2. Не требуется, чтобы вы использовали key кактолько именованные параметры.
  3. Выход является чистым генератором tuple(key, grouped_values), где значения задаются 3-м параметром.
  4. Возможность легко применять функции агрегирования, такие как sum или avg.

Пример использования

import itertools
from operator import itemgetter
from statistics import *

t = [('a',1), ('b',2), ('a',3)]
for k,v in groupby2(t, itemgetter(0), itemgetter(1), sum):
  print(k, v)

При печати

a 4
b 2

Воспроизвести с этим кодом

...