Можем ли мы сделать это с пониманием?

#python #list #dictionary

#python #Список #словарь

Вопрос:

У меня есть список:

 lst = [1, 1, 3, 5, 1, 4, 4]
 

Ожидаемый результат (ключи — это числа, значения — индекс этих чисел):

 {1: [0, 1, 4], 3: [2], 5: [3], 4: [5, 6]}
 

Ну, я знаю, что есть много способов добиться этого.Нравится:

 res = defaultdict(list)
for idx, e in enumerate(lst):
    res[e].append(idx)
 

Или:

 res = {}
for idx, e in enumerate(lst):
    res.setdefault(e, []).append(idx)
 

Интересно, сможем ли мы достичь этого с пониманием dict.
Просто для удовольствия :).


Эффективность не важна.(Было бы лучше быть O(n) ).

Комментарии:

1. Вы могли бы, но это было бы неэффективно

2. @DaniMesejo Любые решения приветствуются.

3. { i : [j for j, e in enumerate(lst) if e == i] for i in set(lst) }

4. @DaniMesejo Не могли бы вы опубликовать это в качестве ответа? Является ли временная сложность O (n ^ 2)?

5. @KevinMayo Меньшее количество строк не является самоцелью, и его принудительное использование часто приводит к снижению производительности. Не то, чтобы понимание (как показано) имело квадратичную сложность, в то время как варианты на основе циклов, которые у вас есть, являются линейными.

Ответ №1:

Наиболее эффективным, на мой взгляд, является:

 from itertools import groupby
from operator import itemgetter

lst = [1, 1, 3, 5, 1, 4, 4]

res = { k : [i for i, _ in group] for k, group in groupby(sorted(enumerate(lst), key=itemgetter(1)), key=itemgetter(1))}
print(res)
 

Вывод

 {1: [0, 1, 4], 3: [2], 4: [5, 6], 5: [3]}
 

Это O(NlogN)

Комментарии:

1. Импортируйте утилиты as gb , as ig и они будут соответствовать более аккуратно: P

2. @schwobaseggl xD

3. Если все перчатки сняты (и я имею в виду действительно сняты), вы можете получить однострочный вариант на основе понимания с линейной сложностью : res = [(d, d[x].append(i)) for d in [defaultdict(list)] for i, x in enumerate(lst)][0][0] : D

Ответ №2:

Я добавляю к этому, поскольку @Kevin Mayo заявил, что эффективность не вызывает беспокойства:

 lst = [1, 1, 3, 5, 1, 4, 4]

lst_s = {key: [i for i, value in enumerate(lst) if value == key]
         for key in set(lst)}

print(lst_s)
# {1: [0, 1, 4], 3: [2], 4: [5, 6], 5: [3]}
 

ВАРИАЦИЯ С range(len(lst))

 lst = [1, 1, 3, 5, 1, 4, 4]

lst_s = {key: [i for i in range(len(lst)) if lst[i] == key]
         for key in set(lst)}

print(lst_s)
# {1: [0, 1, 4], 3: [2], 4: [5, 6], 5: [3]}
 

Ответ №3:

Вот понимание словаря, которое будет выполняться за O (n) время.

 lst = [1, 1, 3, 5, 1, 4, 4]

res = { n:d.setdefault(n,[]).append(i) or d[n] for d in [dict()] for i,n in enumerate(lst) }

print(res)
# {1: [0, 1, 4], 3: [2], 5: [3], 4: [5, 6]}
 

Итак, ответ — да, это можно сделать в понимании списка. Но я бы не рекомендовал это.