Странное поведение itertools.groupby

244 просмотра
0
0 Комментариев

Имею странное поведение groupby. Впечатление такое, что он игнорирует неотсортированные элементы.

>>> from itertools import groupby
>>> arr = [1,2,3,1,2,3,1,2,3]
>>> groups = groupby(arr)
>>> {x: list(y) for x, y in groups}
{1: [1], 2: [2], 3: [3]}
>>> arr.sort()
>>> groups = groupby(arr)
>>> {x: list(y) for x, y in groups}
{1: [1, 1, 1], 2: [2, 2, 2], 3: [3, 3, 3]}

Почему так происходит?

PS: версия 3.6.0


Добавить комментарий

3 Answers

Python Опубликовано 14.12.2018
0

В документации про это написано : The operation of groupby() is similar to the uniq filter in Unix. It generates a break or new group every time the value of the key function changes.

Т.е. каждый раз когда вы натыкаетесь, например, на 1, у вас сбрасывается ключ, поэтому, в вашем случае, вы имеете по одному значению для неотсортированного списка.

from itertools import groupby
arr = [1,2,3,1,2,3,1,1,2,3]
groups = groupby(arr)
print({x: list(y) for x, y in groups})

На выходе получите: {1: [1, 1], 2: [2], 3: [3]}

Добавить комментарий
0

В документации написано:

Generally, the iterable needs to already be sorted on the same key function.

itertools.groupby

Т. е. предварительно последовательность должна быть сортирована с применением того же ключа, что и группировка.
Потому как groupby группирует элементы с одинаковым ключом расположенные последовательно.

В явном виде это можно увидеть в следующем коде:

>>> from itertools import groupby
>>> arr = [1,2,3,1,1,2,2,3,3,1,1,1,2,2,2,3,3,3]
>>> groups = groupby(arr)
>>> [x: list(y) for x, y in groups]
[(1, [1]), (2, [2]), (3, [3]), (1, [1, 1]), (2, [2, 2]), (3, [3, 3]), (1, [1, 1, 1]), (2, [2, 2, 2]), (3, [3, 3, 3])]

Добавить комментарий
0

groupby()* группирует смежные идущие подряд одинаковые значения:

>>> from itertools import groupby
>>> for _, group in groupby("aabbaaabbb"):
...     print(*group)
a a
b b
a a a
b b b

Вы видите только последние группы для каждого ключа, так как вы результат в словарь записываете ({1: [1], 1: [2]} == {1: [2]}).

Если вы хотите, чтобы все одинаковые значения в одну группу попали, то либо надо сортировать ввод:

>>> for _, group in groupby(sorted("aabbaaabbb")):
...     print(*group)
a a a a a
b b b b b

или использовать другие подходы, к примеру, на основе словарей, которые не обращают внимание на порядок элементов (сортировка не нужна):

>>> from collections import Counter
>>> Counter("aabbaaabbb")
Counter({'a': 5, 'b': 5})  # элемент и количество повторений


*Первое предложение в описании groupby():

Make an iterator that returns consecutive keys and groups from the iterable.выделение моё

Добавить комментарий
Напишите свой ответ на данный вопрос.
Scroll Up