Какой идиоматический Python эквивалентен тегу шаблона Django 'regroup'?

http://docs.djangoproject.com/en/dev/ref/templates/builtins/#regroup

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


person Andy Baker    schedule 25.01.2009    source источник


Ответы (3)


Объедините itertools.groupby с _ 2_, чтобы получить довольно хорошее решение:

from operator import itemgetter
from itertools import groupby

key = itemgetter('gender')
iter = groupby(sorted(people, key=key), key=key)

for gender, people in iter:
    print '===', gender, '==='
    for person in people:
        print person
person Jouni K. Seppänen    schedule 25.01.2009
comment
Если источник данных уже отсортирован по ключу, вы можете обойти вызов sorted. См. Следующий комментарий, чтобы просмотреть пример. - person Euribates; 06.02.2015
comment
По-прежнему очень чистое решение, хотя iter является встроенным и, вероятно, не лучшим выбором имени переменной, и print() также был обновлен с Python 3. Для тех, кому интересно, Django внутренне использует groupby для своего тега шаблона regroup. - person Supra621; 05.05.2021

Если источник данных (в данном случае people) уже отсортирован по ключу, вы можете обойти вызов sorted:

iter = groupby(people, key=lambda x:x['gender'])
for gender, people in iter:
    print '===', gender, '==='
    for person in people:
        print person

Примечание: если sorted - общий словарь, нет никаких гарантий порядка; поэтому вы должны позвонить sorted. Здесь я предполагаю, что sorted - это collections.OrderedDict или какая-то другая упорядоченная структура данных.

person Euribates    schedule 06.02.2015

Предыдущие ответы помогли мне решить мою проблему. Для справки в будущем, если у вас есть вложенные данные, например

{'city_name': 'City1', 'comp_name': 'Company1', 'name': 'Branch1'}

и вы хотите сгруппировать по городу, а затем по компании в этом городе, например:

City1
 Company 1
   Branch 1
   Branch 2
 Company 2
   Branch 1
 Company 3
   Branch 1
City2
 Company 2
   Branch 1
 Company 3
   Branch 1
   Branch 2
City3
 Company 1
   Branch 1
 Company 2
   Branch 1
   Branch 2

Я решил это, сделав это:

key = itemgetter('city_name')    
iter = groupby(queryset, key=key) # assuming queryset is already sorted by city_name

for key, group in iter:
    print(key)
    key2 = itemgetter('company_name')
    iter2 = groupby(sorted(group, key=key2), key=key2) # now we must sort by company_name
    for comp, branch in iter2:
        print(comp)
        for b in branch:
            print(b)
person Helpful Lurker    schedule 08.06.2015