Сведения о вопросе

Killer

16:03, 1st July, 2020

Теги

python   iteration    

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

Просмотров: 538   Ответов: 12

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

  • Возьмите список-в этом случае дочерние элементы объективированного элемента lxml
  • Разделите его на группы по некоторым критериям
  • Затем позже повторите каждую из этих групп отдельно.

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

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



  Сведения об ответе

SILA

18:03, 1st July, 2020

Важное примечание: вы должны сначала отсортировать свои данные .


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

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

Это даст вам выход:

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


  Сведения об ответе

PROGA

18:03, 1st July, 2020

Вы можете показать нам свой код?

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


  Сведения об ответе

baggs

18:03, 1st July, 2020

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

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

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

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


  Сведения об ответе

VERSUION

18:03, 1st July, 2020

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, 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 (talk) (Spanish) , "Kung Fu at Dawn with Itertools". Смотрите также исходный код groupby, написанный на языке C.


Ответ

# OP: Yes, you can use `groupby`, e.g. 
[do_something(list(g)) for _, g in groupby(lxml_elements, key=criteria_func)]


  Сведения об ответе

dump

18:03, 1st July, 2020

Еще пример:

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]


  Сведения об ответе

DINO

18:03, 1st July, 2020

ПРЕДУПРЕЖДЕНИЕ:

Список синтаксиса (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, избегая при этом этих надоедливых (для небольших данных) итераторов все вместе.


  Сведения об ответе

repe

18:03, 1st July, 2020

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


  Сведения об ответе

PIRLO

18:03, 1st July, 2020

@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 не будет работать !


  Сведения об ответе

SILA

18:03, 1st July, 2020

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

Вы можете использовать groupby, чтобы сгруппировать вещи для повторения. Вы даете groupby iterable и необязательную функцию ключа / 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])]


  Сведения об ответе

darknet

18:03, 1st July, 2020

Сортировка и группировка

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'}


  Сведения об ответе

park

18:03, 1st July, 2020

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

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)


  Сведения об ответе

SILA

18:03, 1st July, 2020

Вы можете написать собственную функцию groupby:

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


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться