Сообщить об ошибке.

Функция groupby() модуля itertools в Python

Группировка списка списков по ключу

Синтаксис:

import itertools

itertools.groupby(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