Я не смог найти понятного объяснения того, как на самом деле использовать itertools.groupby()
функцию Python . То, что я пытаюсь сделать, это:
- Возьмите список - в этом случае, дети объективированного
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 + "."
Это даст вам вывод:
животные: медведь и утка.
растения: кактус.
транспортные средства: скоростной катер и школьный автобус.
groupby(sorted(my_collection, key=lambda x: x[0]), lambda x: x[0]))
в предположении, что my_collection = [("animal", "bear"), ("plant", "cactus"), ("animal", "duck")]
вы хотите сгруппироватьanimal or plant
Пример на документации по Python довольно прост:
groups = []
uniquekeys = []
for k, g in groupby(data, keyfunc):
groups.append(list(g)) # Store group iterator as a list
uniquekeys.append(k)
Таким образом, в вашем случае data - это список узлов, keyfunc
куда идет логика функции вашего критерия, а затем groupby()
группирует данные.
Вы должны быть осторожны, чтобы отсортировать данные по критериям, прежде чем позвонить, groupby
иначе это не сработает. groupby
Метод на самом деле просто перебирает список и всякий раз, когда ключ меняется, он создает новую группу.
keyfunc
и говорили: «Да, я точно знаю, что это такое, потому что эта документация довольно проста». Невероятно! 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
объекты дают пары ключей-групп, где группа является генератором.
Характеристики
- А. Группируйте последовательные элементы вместе
- B. Сгруппировать все вхождения элемента, с учетом отсортированного итерации
- C. Укажите, как группировать элементы с помощью ключевой функции *
Сравнения
# Define a printer for comparing outputs
>>> def print_groupby(iterable, keyfunc=None):
... for k, g in it.groupby(iterable, keyfunc):
... 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
>>> # keyfunc = lambda s: s.islower() # equivalent
>>> def keyfunc(s):
... """Return a True if a string is lowercase, else False."""
... return s.islower()
>>> print_groupby(sorted("bCAaCacAADBbB"), keyfunc)
key: 'False'--> group: ['A', 'A', 'A', 'B', 'B', 'C', 'C', 'D']
key: 'True'--> group: ['a', 'a', 'b', 'b', 'c']
Пользы
- Анаграммы ( см. Тетрадь )
- Binning
- Группа нечетных и четных чисел
- Группировать список по значениям
- Удалить дубликаты элементов
- Найти индексы повторяющихся элементов в массиве
- Разделить массив на куски размера n
- Найти соответствующие элементы между двумя списками
- Алгоритм сжатия ( см. Записную книжку ) / Кодировка длин серий
- Группировка букв по длине, функция клавиш ( см. Блокнот )
- Последовательные значения за порогом ( см. Записную книжку )
- Найти диапазоны чисел в списке или непрерывных элементов (см. Документы )
- Найти все связанные длинные последовательности
- Возьмите последовательные последовательности, которые удовлетворяют условию ( см. Связанный пост )
Примечание. Некоторые из последних примеров взяты из PyCon (выступления) Виктора Террона (на испанском языке) «Кунг-фу на рассвете с Itertools». Смотрите также groupby
исходный код, написанный на C.
* Функция, в которой все элементы передаются и сравниваются, влияя на результат. Другие объекты с основными функциями включают в себя sorted()
, max()
и min()
.
отклик
# OP: Yes, you can use `groupby`, e.g.
[do_something(list(g)) for _, g in groupby(lxml_elements, criteria_func)]
[''.join(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D
. list()
, tuple()
) или использованы в цикле / понимании для отображения содержимого. Это избыточности, которые автор, скорее всего, исключил для экономии места. Отличный трюк с groupby заключается в запуске кодирования длины в одну строку:
[(c,len(list(cgen))) for c,cgen in groupby(some_string)]
даст вам список из двух кортежей, где первый элемент - это символ, а второй - количество повторений.
Изменить: Обратите внимание, что это то, что отличает семантику 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)
Еще один пример группового - когда ключи не отсортированы. В следующем примере элементы в 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, list (g)) для k, g в groupby (...)], или, если вы часто используете этот синтаксис,
def groupbylist(*args, **kwargs):
return [(k, list(g)) for k, g in groupby(*args, **kwargs)]
и получить доступ к функциональности groupby, избегая этих надоедливых (для маленьких данных) итераторов вместе.
Я хотел бы привести еще один пример, где не работает 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.
есть две группы с транспортным средством, тогда как можно ожидать только одну группу
@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 не будет работать !
Сортировка и групповой
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'}
Как использовать 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
#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)
Эта базовая реализация помогла мне понять эту функцию. Надеюсь, это поможет и другим:
arr = [(1, "A"), (1, "B"), (1, "C"), (2, "D"), (2, "E"), (3, "F")]
for k,g in groupby(arr, lambda x: x[0]):
print("--", k, "--")
for tup in g:
print(tup[1]) # tup[0] == k
-- 1 --
A
B
C
-- 2 --
D
E
-- 3 --
F
Вы можете написать собственную групповую функцию:
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]}