Вопрос-Ответ

How do I use itertools.groupby()?

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

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


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

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

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

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

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

Переведено автоматически
Ответ 1

ВАЖНОЕ ПРИМЕЧАНИЕ: Возможно, вампридется сначала отсортировать свои данные.


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

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

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


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


Ответ 2

itertools.groupby is a tool for grouping items.

From the docs, we glean further what it might do:


# [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 objects yield key-group pairs where the group is a generator.

Features


  • A. Group consecutive items together

  • B. Group all occurrences of an item, given a sorted iterable

  • C. Specify how to group items with a key function *

Comparisons

# 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
>>> # islower = lambda s: s.islower() # equivalent
>>> def islower(s):
... """Return True if a string is lowercase, else False."""
... return s.islower()
>>> print_groupby(sorted("bCAaCacAADBbB"), keyfunc=islower)
key: 'False'--> group: ['A', 'A', 'A', 'B', 'B', 'C', 'C', 'D']
key: 'True'--> group: ['a', 'a', 'b', 'b', 'c']

Uses

Note: Several of the latter examples derive from Víctor Terrón's PyCon (talk) (Spanish), "Kung Fu at Dawn with Itertools". See also the groupby source code written in C.

* A function where all items are passed through and compared, influencing the result. Other objects with key functions include sorted(), max() and min().


Ответ

# OP: Yes, you can use `groupby`, e.g. 
[do_something(list(g)) for _, g in groupby(lxml_elements, criteria_func)]
Ответ 3

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

Ответ 4

Простой трюк с groupby заключается в выполнении кодирования длины в одной строке:

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

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

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

python