Как использовать itertools Python.groupby()?
Я не смог найти понятное объяснение того, как на самом деле использовать Python . Что я пытаюсь сделать, это:
- возьмите список-в этом случае дети объективируются
lxmlэлемент - разделить его на группы на основе определенных критериев
- затем повторите каждую из этих групп отдельно.
я рассмотрел документация и в примеры, но у меня были проблемы, пытаясь применить их за пределами простого списка чисел.
Итак, как я могу использовать itertools.groupby()? Есть ли другая техника, которую я должен использовать? Указатели на хорошее "предварительное" чтение также будут оценены.
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из SQLGROUP 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']использует
- этимология (посмотреть ноутбук)
- Отлежки
- группа четных и нечетных чисел
- сгруппировать список по значениям
- удалить дубликаты элементов
- найти индексы повторяющихся элементов в массиве
- разделить массив на N-размеров кусков
- найти соответствующие элементы двух списков
- алгоритм сжатия (посмотреть ноутбук)/ Выполнить Кодировку Длины
- группировка букв по длине, ключевая функция (посмотреть ноутбук)
- последовательные значения над a порог (посмотреть ноутбук)
- найти диапазоны чисел в список или непрерывного пользования (см. docs)
- найти все связанные длинные последовательности
- возьмите последовательные последовательности, которые удовлетворяют условию (см. по должности)
Примечание: некоторые из последних примеров происходят от 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