import itertools itertools.groupby(iterable, key=None)
iterable
- итерируемая последовательность,key=None
- функция, вычисляющая значение ключа для каждого элемента.Функция groupby()
модуля itertools
создает итератор, который возвращает последовательные ключи и группы из итерируемой последовательности iterable
.
Ключ key
- это функция, вычисляющая значение ключа для каждого элемента. Если ключ не указан или равен None
, ключом по умолчанию является функция тождественности и возвращает элемент без изменений. Как правило, iterable
уже должна быть отсортирована по той же ключевой функции.
Операция itertools.groupby()
похожа на команду uniq
в терминале в Unix. Она генерирует разрыв или новую группу каждый раз, когда изменяется значение ключевой функции, поэтому перед использованием необходимо отсортировать данные с использованием той же ключевой функции. Поведение функции отличается от выражения GROUP BY
в SQL, который объединяет общие элементы независимо от их порядка ввода.
Возвращенная группа сама является итератором, который разделяет базовую итерацию с itertools.groupby()
. Поскольку источник является общим, когда объект groupby()
является расширенным, предыдущая группа больше не отображается. Итак, если эти данные понадобятся позже, они должны быть сохранены в виде списка:
groups = [] uniquekeys = [] data = sorted(data, key=keyfunc) for k, g in groupby(data, keyfunc): # Сохранение группового итератора в виде списка groups.append(list(g)) uniquekeys.append(k)
Функция itertools.groupby()
примерно эквивалентна следующему коду:
class groupby: # [k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B # [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D def __init__(self, iterable, key=None): if key is None: key = lambda x: x self.keyfunc = key self.it = iter(iterable) self.tgtkey = self.currkey = self.currvalue = object() def __iter__(self): return self def __next__(self): self.id = object() while self.currkey == self.tgtkey: self.currvalue = next(self.it) # Exit on StopIteration self.currkey = self.keyfunc(self.currvalue) self.tgtkey = self.currkey return (self.currkey, self._grouper(self.tgtkey, self.id)) def _grouper(self, tgtkey, id): while self.id is id and self.currkey == tgtkey: yield self.currvalue try: self.currvalue = next(self.it) except StopIteration: return self.currkey = self.keyfunc(self.currvalue)
>>> from itertools import groupby # список с повторами >>> x = list('abc' * 3) >>> x # ['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c'] # сортируем список с повторами >>> x.sort() >>> x ['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c'] >>> for i, j in groupby(x): ... print(i, list(j)) ... # a ['a', 'a', 'a'] # b ['b', 'b', 'b'] # c ['c', 'c', 'c']
x = list('AAAABBBCCDAABBB') # Удаление повторяющихся значений в списке >>> [k for k, g in groupby(x)] # ['A', 'B', 'C', 'D', 'A', 'B'] # вывод уникальных значений [k for k, g in groupby(sorted(x))] # ['A', 'B', 'C', 'D']
from itertools import groupby # Есть список заданий [название, действие, очередность] d = [ [ 'task1', 'file find', 1], [ 'task3', 'power off', 1], [ 'task2', 'soft download', 1], [ 'task1', 'file copy', 2], [ 'task2', 'soft install', 2], [ 'task1', 'old file del', 3] ] # ключевая функция сортировки keyfunc = lambda x:x[0] # сортируем список заданий по названию 'x[0]' tasks = sorted(d, key=keyfunc) # при группировке по заданиям применяем # ту же ключевую функцию сортировки >>> for task, action in groupby(tasks , key=keyfunc): ... print(task) ... print('-' * len(task)) # подчеркивание по длине слова ... # сортировка заданий по очередности выполнения ... order_action = sorted(action, key=lambda x:x[2]) ... # вывод ... for _, act, order in order_action: ... print(f' {order} -> {act}') ... # task1 # ----- # 1 -> file find # 2 -> file copy # 3 -> old file del # task2 # ----- # 1 -> soft download # 2 -> soft install # task3 # ----- # 1 -> power off