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

Для иллюстрации я начну со списка из двух кортежей:

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)

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

1 one, one
2 two, two
3 three

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

7
задан Kit 9 August 2010 в 13:47
поделиться

3 ответа

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']
11
ответ дан 6 December 2019 в 09:57
поделиться

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

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

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

6
ответ дан 6 December 2019 в 09:57
поделиться

Из документации:

Операция groupby() похожа на фильтр uniq в Unix. на фильтр 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 ) ) ) )
2
ответ дан 6 December 2019 в 09:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: