Для иллюстрации я начну со списка из двух кортежей:
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 ()
не подходит для этой задачи?
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']
Я думаю, что более чистый способ получить желаемый результат - это следующий.
>>> 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 ()
находится только над уникальными ключами, а не над всем набором данных
Из документации:
Операция 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 ) ) ) )