Как использовать itertools.groupby, когда значение ключа находится в элементах итерируемого? - PullRequest
7 голосов
/ 09 августа 2010

Чтобы проиллюстрировать это, я начинаю со списка из двух кортежей:

import itertools
import operator

raw = [(1, "one"),
       (2, "two"),
       (1, "one"),
       (3, "three"),
       (2, "two")]

for key, grp in itertools.groupby(raw, key=lambda item: item[0]):
    print key, list(grp).pop()[1]

Выходы:

1 one
2 two
1 one
3 three
2 two

В попытке выяснить, почему:

for key, grp in itertools.groupby(raw, key=lambda item: item[0]):
    print key, list(grp)

# ---- OUTPUT ----
1 [(1, 'one')]
2 [(2, 'two')]
1 [(1, 'one')]
3 [(3, 'three')]
2 [(2, 'two')]

Даже это даст мне тот же результат:

for key, grp in itertools.groupby(raw, key=operator.itemgetter(0)):
    print key, list(grp)

Я хочу получить что-то вроде:

1 one, one
2 two, two
3 three

Я думаю, это потому, что ключ находится внутри кортежа в списке, когда на самом деле кортеж перемещается как единое целое. Есть ли способ получить желаемый результат? Может быть, groupby() не подходит для этой задачи?

Ответы [ 3 ]

11 голосов
/ 09 августа 2010

groupby кластеров последовательных элементов итерируемого, имеющих одинаковый ключ.Чтобы получить желаемый результат, вы должны сначала отсортировать raw.

for key, grp in itertools.groupby(sorted(raw), key=operator.itemgetter(0)):
    print key, map(operator.itemgetter(1), grp)

# 1 ['one', 'one']
# 2 ['two', 'two']
# 3 ['three']
6 голосов
/ 10 августа 2010

Я думаю, что более чистый способ получить желаемый результат заключается в следующем.

>>> from collections import defaultdict
>>> d=defaultdict(list)
>>> for k,v in raw:
...  d[k].append(v)
... 
>>> for k,v in sorted(d.items()):
...  print k, v
... 
1 ['one', 'one']
2 ['two', 'two']
3 ['three']

building d - это O (n), и теперь sorted() - это просто уникальные ключи вместо целыхНабор данных

2 голосов
/ 09 августа 2010

Из документов :

Операция groupby () аналогична в фильтр Uniq в Unix. Это генерирует перерыв или новую группу каждый время значение ключевой функции изменения (именно поэтому обычно необходимо отсортировать данные используя ту же функцию клавиш). Тот поведение отличается от GROUP BY SQL который объединяет общие элементы независимо от их порядка ввода.

Поскольку вы все равно сортируете кортежи лексикографически, вы можете просто позвонить sorted:

for key, grp in itertools.groupby( sorted( raw ), key = operator.itemgetter( 0 ) ):
    print( key, list( map( operator.itemgetter( 1 ), list( grp ) ) ) )
...