Вопрос

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

  • Составьте список — в данном случае это дети объективированного lxml элемент
  • Разделите его на группы по некоторым критериям.
  • Затем позже повторите каждую из этих групп отдельно.

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

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

Это было полезно?

Решение

ВАЖНАЯ ЗАМЕТКА: Вы должны отсортируйте ваши данные первый.


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

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 + "."

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

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

Другие советы

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

Пример в документации 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 на самом деле метод просто перебирает список, и всякий раз, когда ключ меняется, он создает новую группу.

Хитрость с groupby заключается в том, чтобы выполнить кодирование длины в одной строке:

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

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

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

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 объекты дают пары ключ-группа, где группа является генератором.

Функции

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

Сравнения

# 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 function
>>> 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 Виктора Террона. (разговаривать) (Испанский язык), «Кунг-фу на рассвете с Itertools».См. также groupbyисходный код написано на языке С.


Ответ

# OP: Yes, you can use `groupby`, e.g. 
[do_something(list(g)) for _, g in groupby(lxml_elements, key=criteria_func)]

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

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)

Еще один пример группировки — когда ключи не отсортированы.В следующем примере элементы в xx сгруппированы по значениям в yy.В этом случае сначала выводится один набор нулей, затем набор единиц, а затем снова набор нулей.

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]

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

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

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

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

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

Вместо list(groupby(...)) попробуйте [(k, list(g)) for k,g в groupby(...)], или, если вы часто используете этот синтаксис,

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

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

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

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.

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

@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 не будет работать!

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

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

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

Вот пример группировки с использованием сопрограммы для группировки по счетчику, она использует вызываемый ключ (в данном случае, 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])]

Сортировка и группировка

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'}

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

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)

Вы можете написать собственную функцию группировки:

           def groupby(data):
                kv = {}
                for k,v in data:
                    if k not in kv:
                         kv[k]=[v]
                    else:
                        kv[k].append(v)
           return kv

     Run on ipython:
       In [10]: data = [('a', 1), ('b',2),('a',2)]

        In [11]: groupby(data)
        Out[11]: {'a': [1, 2], 'b': [2]}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top