Как эффективно классифицировать список словарей по значению ключа в python?

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

dictList = [
            {'name': 'name1', 'type': 'type1', 'id': '14464'}, 
            {'name': 'name2', 'type': 'type1', 'id': '26464'},
            {'name': 'name3', 'type': 'type3', 'id': '36464'},
            {'name': 'name4', 'type': 'type5', 'id': '43464'},
            {'name': 'name5', 'type': 'type2', 'id': '68885'}
            ]

Это код, который я сейчас использую:

while len(dictList):
    category = [l for l in dictList if l['type'] == dictList[0]['type']]
    processingMethod(category)
    for item in category:
        dictList.remove(item)

Эта итерация в приведенном выше списке даст мне следующий результат:

Iteration 1:
            category = [
                        {'name': 'name1', 'type': 'type1', 'id': '14464'}, 
                        {'name': 'name2', 'type': 'type1', 'id': '26464'},
                        ]

Iteration 2:
            category = [
                        {'name': 'name3', 'type': 'type3', 'id': '36464'}
                        ]

Iteration 3:
            category = [
                        {'name': 'name4', 'type': 'type5', 'id': '43464'}
                        ]

Iteration 4:
            category = [
                        {'name': 'name5', 'type': 'type2', 'id': '68885'}
                        ]

Каждый раз я получаю категорию, обрабатываю ее и, наконец, удаляю обработанные элементы, чтобы перебрать оставшиеся элементы, пока не останется ни одного элемента. Есть идеи, чтобы сделать это лучше?

2 ответа

Решение

Ваш код может быть переписан с помощью itertools.groupby

for _, category in itertools.groupby(dictList, key=lambda item:item['type']):
    processingMethod(list(category))

Или, если processingMethod может обрабатывать iterable,

for _, category in itertools.groupby(dictList, key=lambda item:item['type']):
    processingMethod(category)

Если l['type'] Хашим для каждого l в dictListВот возможное, несколько элегантное решение:

bins = {}

for l in dictList:
    if l['type'] in bins:
        bins[l['type']].append(l)
    else:
        bins[l['type']] = [l]

for category in bins.itervalues():
   processingMethod(category)

Идея в том, что сначала мы разберем все lс мусорными ведрами, используя l['type'] в качестве ключа; во-вторых, мы обработаем каждую корзину.

Если l['type'] не гарантируется быть хэшируемым для каждого l в dictList, подход по сути тот же, но нам придется использовать список кортежей вместо dict, что означает, что это немного менее эффективно:

bins = []

for l in dictList:
    for bin in bins:
        if bin[0] == l['type']:
            bin[1].append(l)
            break
    else:
        bins.append((l['type'], [l]))

for _, category in bins:
   processingMethod(category)
Другие вопросы по тегам