Увеличение ценностей диктата с пониманием диктата - PullRequest
0 голосов
/ 20 сентября 2018

Я пытаюсь сделать следующее выражение с пониманием dict и троичной операцией в python:

for num in ar:
     if num in seen_dict:
         seen_dict[num] += 1
     else:
         seen_dict[num] = 1

Я пробовал это:

seen_dict = { num: seen_dict[num] += 1 for num in ar if num in seen_dict else seen_dict[num] = 1}

и несколько его перестановок, ноЯ продолжаю получать синтаксические ошибки.Можно ли делать то, что я хочу?

ОБНОВЛЕНИЕ

Это правильный синтаксис, но не мой dict возвращается только с 1: seen_dict = { num: (seen_dict[num] + 1) if num in seen_dict else 1 for num in ar }

Может кто-нибудь объяснить, почему это не работает так же, как цикл for?Спасибо.

Ответы [ 3 ]

0 голосов
/ 20 сентября 2018

Похоже, вы пытаетесь получить появления всех значений в списке.(Если это не так, пожалуйста, дайте мне знать.) Вот как я мог бы подойти к этому:

seen_dict = {num: arr.count(num) for num in list(set(arr))}

Объяснение:

  • arr.count(num): метод list.count(element) возвращаетчисло появлений element в list
  • set(arr): создает объект set, который при преобразовании обратно в список удаляет все дубликаты, или, другими словами, получает все различные значенияlist
  • list(set(arr)): различные значения в arr

В возвращаемом словаре будут пары ключ-значение number - # of appearances of number in arr.

0 голосов
/ 20 сентября 2018

Не.Это кажется , как если бы это использовалось в качестве диктата, это хорошая идея, но на самом деле это ужасная ловушка.Используйте collections.Counter:

import counts

seen_dict = collections.Counter(ar)

или, если вы не хотите этого делать, придерживайтесь цикла.

Проблема с попыткой использованияДиктовое понимание заключается в том, что в этом случае нет хорошего способа поддерживать состояние или чередовать вычисления значений каждого ключа.Каждое значение должно быть вычислено в одном выражении.Напротив, лучший способ решить вашу проблему с подсчетом - сделать один проход через ar и обновлять счет каждого элемента по мере продвижения.

Ограничения понимания приводят к ужасно неэффективным попыткам, таким как

seen_dict = {val: ar.count(val) for val in ar}

, который делает количество проходов на ar равным длине ar, или немного более эффективному, но все еще ужасно неоптимальному

seen_dict = {val: ar.count(val) for val in set(ar)}

, которое нужно только сделать len(set(ar)) проходит, или для людей , немного более знакомых со стандартной библиотекой ,

from itertools import groupby
seen_dict = {val: sum(1 for _ in group) for val, group in groupby(sorted(ar))}

, которая, по крайней мере, не является квадратичным временем, но все еще O (nlogn) для длины-n ar.

Если мы запустим синхронизацию из этих четырех фрагментов с входом list(range(10000)):

from collections import Counter
from itertools import groupby
from timeit import timeit

ar = list(range(10000))

print(timeit('Counter(ar)', number=1, globals=globals()))
print(timeit('{val: ar.count(val) for val in ar}', number=1, globals=globals()))
print(timeit('{val: ar.count(val) for val in set(ar)}', number=1, globals=globals()))
print(timeit('{val: sum(1 for _ in group) for val, group in groupby(sorted(ar))}',
             number=1, globals=globals()))

Мы получим следующий вывод:

0.0005530156195163727
1.0503493696451187
1.0463058911263943
0.00422721728682518

Counter заканчивается через полмисекунды, в то время как фрагменты count занимают секунду.(Версия set имеет меньшее время выполнения из-за какого-то эффекта первого запуска, замедляющего работу другой версии; переключение порядка версий set и не set обычно меняет относительную синхронизацию этих версийДедупликация set не помогает в этом тесте, так как на входе нет дубликатов.)

Для более длинного ввода полагаться на count было бы еще более непомерно дорого.Полагаясь на count, можно легко потратить несколько дней на ввод, который Counter все равно завершится менее чем за секунду.

0 голосов
/ 20 сентября 2018

Здесь все было намного проще, чем я думал.В основном, вы хотите, чтобы количество раз, что-то происходило в списке, что вы можете сделать, сказав ar.count(num).Вы можете легко сделать это без троичных операторов, таких как:

ar = [1,2,3,2]
seen_dict = { num:ar.count(num) for num in ar}
print(seen_dict)# {1:1, 2:2, 3:1}
...