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



Я не смог найти понятное объяснение того, как на самом деле использовать Python . Что я пытаюсь сделать, это:




  • возьмите список-в этом случае дети объективируются lxml элемент

  • разделить его на группы на основе определенных критериев

  • затем повторите каждую из этих групп отдельно.


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



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

434   11  

11 ответов:

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

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

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 - это список кортежей, где первый элемент в каждом кортеже-это группа, к которой принадлежит второй элемент.

The 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 docs довольно прост:

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

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

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

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

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

еще пример:

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 группируются по значениям в 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]

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

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

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

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

особенности

  • A. группируйте последовательные элементы вместе
  • 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 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)]

Я хотел бы привести еще один пример, где 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, в то время как можно было ожидать только одну группу

@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)]

как вы можете видеть, есть два o и два e, но они попали в отдельные группы. Именно тогда я понял, что вам нужно отсортировать список, переданный функции 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 Python.groupby()?

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

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])]

сортировка и 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'}

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

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)

Comments

    Ничего не найдено.