2013-03-22 4 views
5

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

Это достаточно легко сделать:

# using defaultdict 
lookup = collections.defaultdict(list) 
for item in items: 
    lookup[key(item)].append(item) 

# or, using plain dict 
lookup = {} 
for item in items: 
    lookup.setdefault(key(item), []).append(item) 

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

def grouped(iterable, key): 
    result = {} 
    for item in iterable: 
     result.setdefault(key(item), []).append(item) 
    return result 

lookup = grouped(items, key) 

Это отличается от itertools.groupby в нескольких важных направлениях. Для того, чтобы получить тот же результат с groupby, вы должны сделать это, что немного некрасиво:

lookup = dict((k, list(v)) for k, v in groupby(sorted(items, key=key), key)) 

Некоторые примеры:

>>> items = range(10) 
>>> grouped(items, lambda x: x % 2) 
{0: [0, 2, 4, 6, 8], 1: [1, 3, 5, 7, 9]} 

>>> items = 'hello stack overflow how are you'.split() 
>>> grouped(items, len) 
{8: ['overflow'], 3: ['how', 'are', 'you'], 5: ['hello', 'stack']} 

Есть ли лучший способ?

+1

Я не вижу, как это «достаточно часто используется для использования». Я использую его редко, и когда мне нужно, использование 'defaultdict' просто идеально. AFAIK нет встроенного, который делает то, что вы хотите сам по себе. – Bakuriu

+0

Возможно, вы правы, но часть меня думает, что это так же справедливо для встроенного, как groupby. – FogleBird

ответ

3

Я также разместил этот вопрос на comp.lang.python, и, похоже, консенсус заключается в том, что на самом деле это недостаточно распространено, чтобы гарантировать встроенную функцию. Поэтому лучше использовать очевидные подходы. Они работают, и они читаемы.

# using defaultdict 
lookup = collections.defaultdict(list) 
for item in items: 
    lookup[key(item)].append(item) 

# or, using plain dict 
lookup = {} 
for item in items: 
    lookup.setdefault(key(item), []).append(item) 

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

+1

См. Мой ответ ниже, как вы можете извлечь функцию, чтобы сделать то же самое, что и выше, но используя примерно тот же API, что и 'groupby'. – tobych

1

Если вы хотите что-то с примерно такой же API, как groupby, вы можете использовать:

def groupby2(iterable, keyfunc): 
    lookup = collections.defaultdict(list) 
    for item in iterable: 
     lookup[keyfunc(item)].append(item) 
    return lookup.iteritems() 

Так что это так же, как ваш пример выше, но сделано в функции возвращающей iteritems из таблицы поиска вас» ve построенный.

Смежные вопросы