Как использовать itertools.groupby Питона ()?

голоса
364

Я не смог найти понятное объяснение того , как на самом деле использовать Питона itertools.groupby()функцию. То , что я пытаюсь сделать это:

  • Возьмите список - в этом случае, дети объектного lxmlэлемента
  • Разделите его на группы по определенным критериям
  • Позже итерация по каждому из этих групп в отдельности.

Я рассмотрел документацию и примеры , но у меня были проблемы при попытке применить их за пределы простого списка чисел.

Итак, как же я использование itertools.groupby()? Есть еще один метод , который я должен использовать? Указатели на хорошее «обязательное условии» чтение также будут оценены.

Задан 03/08/2008 в 19:27
источник пользователем
На других языках...                            


12 ответов

голоса
523

Как сказал Sebastjan, сначала нужно сортировать данные. Это важно.

Часть я не получаю, что в примере строительства

groups = []
uniquekeys = []
for k, g in groupby(data, keyfunc):
   groups.append(list(g))    # Store group iterator as a list
   uniquekeys.append(k)

kявляется текущим ключом группировки, и gэто итератор , который вы можете использовать для итерации по группе , определяемой этот ключ группирования. Другими словами, groupbyсам итератор возвращает итераторы.

Вот пример того, что, используя четкие имена переменных:

from itertools import groupby

things = [("animal", "bear"), ("animal", "duck"), ("plant", "cactus"), ("vehicle", "speed boat"), ("vehicle", "school bus")]

for key, group in groupby(things, lambda x: x[0]):
    for thing in group:
        print "A %s is a %s." % (thing[1], key)
    print " "

Это даст вам результат:

Медведь является животным.
Утка является животным.

Кактус это растение.

Скорость лодки представляет собой транспортное средство.
Школьный автобус представляет собой транспортное средство.

В этом примере, thingsсписок кортежей , где первый элемент в каждом кортеже группа второй элемент принадлежит.

groupby()Функция принимает два аргумента: (1) данные в группу и (2) функцию , чтобы сгруппировать его с.

Здесь, lambda x: x[0]говорит , groupby()чтобы использовать первый элемент в каждом кортеже в качестве ключа группировки.

В приведенном выше forзаявлении, groupbyвозвращает три пары (ключ, группа итератора) - один раз для каждого уникального ключа. Вы можете использовать возвращаемый итератор для перебора каждого отдельного элемента в этой группе.

Вот немного другой пример с теми же данными, используя список понимание:

for key, group in groupby(things, lambda x: x[0]):
    listOfThings = " and ".join([thing[1] for thing in group])
    print key + "s:  " + listOfThings + "."

Это даст вам результат:

животные: медведь и уток.
растения: кактус.
транспортные средства: скоростной катер и школьный автобус.

Ответил 10/08/2008 d 19:45
источник пользователем

голоса
65

Можете ли вы показать нам свой код?

Пример на документах Python достаточно прост:

groups = []
uniquekeys = []
for k, g in groupby(data, keyfunc):
    groups.append(list(g))      # Store group iterator as a list
    uniquekeys.append(k)

Так что в вашем случае данные списка узлов, keyfunc где логика вашей функции критериев идет , а затем groupby()группирует данные.

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

Ответил 03/08/2008 d 19:40
источник пользователем

голоса
32

Neato трюк с GroupBy это запустить кодирование длины в одной строке:

[(c,len(list(cgen))) for c,cgen in groupby(some_string)]

даст вам список из 2-кортежей, где первый элемент полукокс и второе это число повторений.

Изменить: Обратите внимание , что это то , что отличает itertools.groupbyот SQL GROUP BYсемантики: itertools не делает (и вообще не может) сортировать итератор заранее, поэтому группы с таким же «ключ» не слиты.

Ответил 01/09/2008 d 00:27
источник пользователем

голоса
21

Другой пример:

for key, igroup in itertools.groupby(xrange(12), lambda x: x // 5):
    print key, list(igroup)

результаты в

0 [0, 1, 2, 3, 4]
1 [5, 6, 7, 8, 9]
2 [10, 11]

Обратите внимание, что igroup итератор (суб-итератор, как документация называет).

Это полезно для отрывов генератора:

def chunker(items, chunk_size):
    '''Group items in chunks of chunk_size'''
    for _key, group in itertools.groupby(enumerate(items), lambda x: x[0] // chunk_size):
        yield (g[1] for g in group)

with open('file.txt') as fobj:
    for chunk in chunker(fobj):
        process(chunk)

Другой пример GroupBy - когда ключи не сортируются. В следующем примере, элементы в ом сгруппированы по значениям в уу. В этом случае один набор нулей выводится первым, а затем с помощью набора из них, а затем снова множеством нулей.

xx = range(10)
yy = [0, 0, 0, 1, 1, 1, 0, 0, 0, 0]
for group in itertools.groupby(iter(xx), lambda x: yy[x]):
    print group[0], list(group[1])

Производит:

0 [0, 1, 2]
1 [3, 4, 5]
0 [6, 7, 8, 9]
Ответил 21/01/2013 d 17:54
источник пользователем

голоса
17

ПРЕДУПРЕЖДЕНИЕ:

Список синтаксиса (GroupBy (...)) не будет работать так, что вы собираетесь. Кажется, чтобы уничтожить внутренние объекты итераторов, так что использование

for x in list(groupby(range(10))):
    print(list(x[1]))

будет производить:

[]
[]
[]
[]
[]
[]
[]
[]
[]
[9]

Вместо этого, из списка (GroupBy (...)), попробуйте [(к, лист (г)) для к, г в GroupBy (...)], или если вы используете этот синтаксис часто,

def groupbylist(*args, **kwargs):
    return [(k, list(g)) for k, g in groupby(*args, **kwargs)]

и получить доступ к функциональным возможностям GroupBy, избегая при этом те досадные (для небольших данных) итераторы все вместе.

Ответил 16/11/2013 d 01:39
источник пользователем

голоса
11

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

groupby Объекты дают пары ключ-группы, где группа является генератором.

Особенности

  • А. Группа последовательных элементов вместе ( по аналогии с unique_justseenрецептом)
  • B. Группа все вхождения элемента, учитывая отсортированный итерацию
  • C. Укажите, как группировать элементы с ключевой функцией

Сравнения

# Define a printer for comparing outputs
>>> def print_groupby(iterable, key=None):
...    for k, g in it.groupby(iterable, key):
...        print("key: '{}'--> group: {}".format(k, list(g)))


# Feature A: group consecutive occurrences
>>> print_groupby("BCAACACAADBBB")
key: 'B'--> group: ['B']
key: 'C'--> group: ['C']
key: 'A'--> group: ['A', 'A']
key: 'C'--> group: ['C']
key: 'A'--> group: ['A']
key: 'C'--> group: ['C']
key: 'A'--> group: ['A', 'A']
key: 'D'--> group: ['D']
key: 'B'--> group: ['B', 'B', 'B']

# Feature B: group all occurrences
>>> print_groupby(sorted("BCAACACAADBBB"))
key: 'A'--> group: ['A', 'A', 'A', 'A', 'A']
key: 'B'--> group: ['B', 'B', 'B', 'B']
key: 'C'--> group: ['C', 'C', 'C']
key: 'D'--> group: ['D']

# Feature C: group by a key
>>> key = lambda x: x.islower()
>>> print_groupby(sorted("bCAaCacAADBbB"), key)
key: 'False'--> group: ['A', 'A', 'A', 'B', 'B', 'C', 'C', 'D']
key: 'True'--> group: ['a', 'a', 'b', 'b', 'c']

Пользы

Некоторые из последних примеров вытекают из PyCon разговора Víctor Terrón в ( на английском языке) (испанский) , кунг - фу на рассвете с Itertools . Для тех , кто заинтересован, вот исходный код для groupbyнаписан на C.

Ответил 25/08/2017 d 02:26
источник пользователем

голоса
10

Я хотел бы привести еще один пример, где GroupBy без рода не работает. Адаптировано из примера Джеймса Сулак

from itertools import groupby

things = [("vehicle", "bear"), ("animal", "duck"), ("animal", "cactus"), ("vehicle", "speed boat"), ("vehicle", "school bus")]

for key, group in groupby(things, lambda x: x[0]):
    for thing in group:
        print "A %s is a %s." % (thing[1], key)
    print " "

выход

A bear is a vehicle.

A duck is a animal.
A cactus is a animal.

A speed boat is a vehicle.
A school bus is a vehicle.

Есть две группы с VEHICULE, в то время как можно было бы ожидать только одну группу

Ответил 07/05/2013 d 21:09
источник пользователем

голоса
7

@CaptSolo, я попробовал ваш пример, но это не сработало.

from itertools import groupby 
[(c,len(list(cs))) for c,cs in groupby('Pedro Manoel')]

Вывод:

[('P', 1), ('e', 1), ('d', 1), ('r', 1), ('o', 1), (' ', 1), ('M', 1), ('a', 1), ('n', 1), ('o', 1), ('e', 1), ('l', 1)]

Как вы можете видеть, есть два Выходов и два е, но они попали в отдельные группы. Вот тогда я понял, что вам нужно отсортировать список, переданный функции GroupBy. Таким образом, правильное использование будет:

name = list('Pedro Manoel')
name.sort()
[(c,len(list(cs))) for c,cs in groupby(name)]

Вывод:

[(' ', 1), ('M', 1), ('P', 1), ('a', 1), ('d', 1), ('e', 2), ('l', 1), ('n', 1), ('o', 2), ('r', 1)]

Просто вспомнить, если список не отсортирован, функция GroupBy не будет работать !

Ответил 15/10/2009 d 16:41
источник пользователем

голоса
5

Как использовать itertools.groupby Питона ()?

Вы можете использовать GroupBy группировать вещи перебирать. Вы даете GroupBy итератор, и необязательный ключ функцию / вызываемой с помощью которого можно проверить элементы , как они вышли из итерации, и она возвращает итератор , который дает два-кортеж результата ключ отозваны и фактическим элементы в другая итерация. С помощью:

groupby(iterable[, keyfunc]) -> create an iterator which returns
(key, sub-iterator) grouped by each value of key(value).

Вот пример GroupBy с использованием сопрограммы группы по подсчетам, она использует ключ отозван (в данном случае coroutine.send) просто выплюнуть счетчик для однако многих итераций и сгруппированный суб-итератор элементов:

import itertools


def grouper(iterable, n):
    def coroutine(n):
        yield # queue up coroutine
        for i in itertools.count():
            for j in range(n):
                yield i
    groups = coroutine(n)
    next(groups) # queue up coroutine

    for c, objs in itertools.groupby(iterable, groups.send):
        yield c, list(objs)
    # or instead of materializing a list of objs, just:
    # return itertools.groupby(iterable, groups.send)

list(grouper(range(10), 3))

печать

[(0, [0, 1, 2]), (1, [3, 4, 5]), (2, [6, 7, 8]), (3, [9])]
Ответил 27/07/2015 d 18:06
источник пользователем

голоса
3

Сортировка и GroupBy

from itertools import groupby

val = [{'name': 'satyajit', 'address': 'btm', 'pin': 560076}, {'name': 'Mukul', 'address': 'Silk board', 'pin': 560078}, {'name': 'Preetam', 'address': 'btm', 'pin': 560076}]


for pin, list_data in groupby(sorted(val, key=lambda k: k['pin']),lambda x: x['pin']):
...     print pin
...     for rec in list_data:
...             print rec
... 
o/p:

560076
{'name': 'satyajit', 'pin': 560076, 'address': 'btm'}
{'name': 'Preetam', 'pin': 560076, 'address': 'btm'}
560078
{'name': 'Mukul', 'pin': 560078, 'address': 'Silk board'}
Ответил 01/08/2017 d 07:14
источник пользователем

голоса
2

Один полезный пример, который я наткнулся может быть полезно:

from itertools import groupby

#user input

myinput = input()

#creating empty list to store output

myoutput = []

for k,g in groupby(myinput):

    myoutput.append((len(list(g)),int(k)))

print(*myoutput)

Пример ввода: 14445221

Пример вывода: (1,1) (3,4) (1,5) (2,2) (1,1)

Ответил 18/06/2017 d 17:16
источник пользователем

голоса
-1

Сделать итератор, который возвращает последовательные ключи и группы из Iterable. Ключ является функцией вычисления значения ключа для каждого элемента.

import itertools

for k,group in  itertools.groupby([['subject1','english'],['subject2','kannada']]):
for g in group:
    print(f'{k[0]} is {g[1]}')
# output : 
subject1 is english
subject2 is kannada
Ответил 23/08/2018 d 06:44
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more