Как использовать itertools Python.groupby()?
Я не смог найти понятное объяснение того, как на самом деле использовать Python . Я пытаюсь сделать вот что:--4-->
- возьмите список-в этом случае дети объективированного
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
iterator сам возвращает итераторы.
вот пример этого, используя более четкую переменную имена:
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
метод фактически просто повторяет список и всякий раз, когда ключ изменяется, он создает новая группа.
neato трюк с groupby, чтобы запустить кодировку длины в одной строке:
[(c,len(list(cgen))) for c,cgen in groupby(some_string)]
даст вам список из 2-кортежей, где первый элемент является char, а второй-количество повторений.
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 является итератором (суб-итератором, как его называет документация).
это полезно для chunking генератора:
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]
вместо list(groupby(...)), попробуйте [(k, list (g)) для 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)]
как вы можете видеть, есть два " О "и два "е", но они попали в отдельные группы. Именно тогда я понял, что вам нужно отсортировать список, переданный функции 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 iterable и необязательный ключ 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)