python: быстрый способ накопить в словаре списки значений

есть задача:

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

подскажите, есть ли более производительный код, чем решение в лоб:

res = dict()
for i, v in enumerate(arr):
    if v in arr:
        res[v].append(i)
    else:
        res[v] = [i]

если использовать get - это замедляет код в 2-3 раза:

res = dict()
for i, v in enumerate(arr):
    res[v] = res.get(v, []) + [i]

Ответы (1 шт):

Автор решения: CrazyElf

Из того, что я попробовал на моих тестовых данных быстрее оказался defaultdict. Но вообще нужно всё-таки приводить параметры ваших данных: тип и размерность. На разных данных могут быть разные результаты.

import random
from collections import defaultdict

def func1(arr):
    res = dict()
    for i, v in enumerate(arr):
        if v in res:
            res[v].append(i)
        else:
            res[v] = [i]

def func2(arr):
    res = dict()
    for i, v in enumerate(arr):
        res[v] = res.get(v, []) + [i]

def func3(arr):
    res = dict()
    for i, v in enumerate(arr):
        res.setdefault(v, []).append(i)

def func4(arr):
    res = defaultdict(list)
    for i, v in enumerate(arr):
        res[v].append(i)

arr = [random.randint(0, 100) for _ in range(1000)]
assert func1(arr) == func2(arr)
assert func2(arr) == func3(arr)
assert func3(arr) == func4(arr)

%timeit func1(arr)
%timeit func2(arr)
%timeit func3(arr)
%timeit func4(arr)

Вывод:

10000 loops, best of 5: 167 µs per loop
1000 loops, best of 5: 270 µs per loop
10000 loops, best of 5: 192 µs per loop
10000 loops, best of 5: 144 µs per loop

С itertools.groupby я что-то недоразобрался )

Так то хорошо бы ещё попробовать Numpy и Numba, но нужно знать, какие у вас данные.

→ Ссылка