Понимание словаря для значений списка

Я хочу знать, есть ли более Pythonic способ сделать следующее, возможно, используя словарное понимание:

A = some list
D = {}
for i,v in enumerate(A):
    if v in D:
        D[v].append(i)
    else:
        D[v] = [i]

person lorenzocastillo    schedule 11.04.2016    source источник


Ответы (2)


Использование defaultdict:

from collections import defaultdict
D = defaultdict(list)
[D[v].append(i) for i, v in enumerate(A)]

Использование setdefault:

D = {}
[D.setdefault(v, []).append(i) for i, v in enumerate(A)]

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

from itertools import groupby
from operator import itemgetter
{v: ids for v, ids in groupby(enumerate(sorted(A)), itemgetter(1))}

Выступления:

from collections import defaultdict
from itertools import groupby
from operator import itemgetter
from random import randint

A = tuple(randint(0, 100) for _ in range(1000))

def one():
    D = defaultdict(list)
    [D[v].append(i) for i, v in enumerate(A)]

def two():
    D = {}
    [D.setdefault(v, []).append(i) for i, v in enumerate(A)]

def three():
    {v: ids for v, ids in groupby(enumerate(sorted(A)), itemgetter(1))}


from timeit import timeit

for func in (one, two, three):
    print(func.__name__ + ':', timeit(func, number=1000))

Итоги (как всегда, самая простая победа):

one: 0.25547646999984863
two: 0.3754340969971963
three: 0.5032370890003222
person aluriak    schedule 11.04.2016
comment
Действительно ли Pythonic использовать списки просто как средство выполнения работы? Признаюсь, я сталкивался с этой проблемой раньше и рассматривал компоновку списков как способ сделать это, но это кажется хакерским. Однако, кроме этого, я согласен с defaultdict как с самым ясным ответом. - person dwanderson; 11.04.2016
comment
Другой способ — использовать map, но понимание списка гораздо более читабельно и, как правило, рекомендуется. - person aluriak; 11.04.2016

Вы можете сделать следующее

d = collections.defaultdict(list)
for i,v in enumerate(A):
    d[v].append(i)

Вы можете видеть, что значения результирующего словаря равны lists, элементы которых должны быть созданы при обходе. Если вы настаиваете на выполнении диктофона, вы должны сначала найти все (value, [indices]), а затем выполнить диктофон [(k,[v])], что просто означает дополнительную акробатику без какой-либо пользы.

person C Panda    schedule 11.04.2016
comment
На самом деле, пришел к этому решению, посмотрев на выбранный ответ. - person lorenzocastillo; 11.04.2016
comment
@ user2804747 Отлично. Если вы имеете дело с преобразованиями данных, используя в основном словари, модуль collections стоит прочитать. - person C Panda; 11.04.2016