#python #python-3.x #list-comprehension
Вопрос:
Я был уверен, что будет один лайнер для преобразования списка в словарь, где элементы в списке были ключами, а словарь не имел значений.
Единственный способ, который я мог найти для этого, был отвергнут.
«Использование понимания списка, когда результат игнорируется, вводит в заблуждение и неэффективно. for
Петля лучше»
myList = ['a','b','c','d']
myDict = {}
x=[myDict.update({item:None}) for item in myList]
>>> myDict
{'a': None, 'c': None, 'b': None, 'd': None}
Это работает, но есть ли лучший способ сделать это?
Комментарии:
1. Ключи без значений? Разве это не набор?
2. Хм, я только что понял, что могу замариновать набор, так что, возможно, я буду использовать набор, но теперь мне нужно убедиться, что я могу найти значение в наборе так быстро, как только смогу, значение в словаре, и я могу сказать, что моя жена хочет, чтобы я перестал работать и вернулся домой.
3. @PyNEwbie: Тестирование членства в наборах в основном эквивалентно поиску ключей в словарях (оба используют хэши). Что еще более важно, если вы собираетесь выполнять операции с наборами (объединение, пересечение, различие и т. Д.), То их проще и быстрее выполнять с наборами, чем со словарями.
4. @S. Лотт при поиске элемента в диктанте дает вам O(1) время доступа, в то время как упорядоченные наборы(по умолчанию) дают вам O(n), а упорядоченные наборы(те, которые у вас есть, например, дополнительные вычислительные затраты) дают вам O(логин).
Ответ №1:
Воспользуйся dict.fromkeys
:
>>> my_list = [1, 2, 3]
>>> dict.fromkeys(my_list)
{1: None, 2: None, 3: None}
Значения по умолчанию None
равны , но вы можете указать их в качестве необязательного аргумента:
>>> my_list = [1, 2, 3]
>>> dict.fromkeys(my_list, 0)
{1: 0, 2: 0, 3: 0}
Из документов:
a.из ключей(seq[, значение]) Создает новый словарь с ключами из seq и значениями, установленными в значение.
dict.fromkeys-это метод класса, который возвращает новый словарь. значение по умолчанию равно Нет. Новое в версии 2.3.
Ответ №2:
Вы могли бы использовать набор вместо диктанта:
>>> myList=['a','b','c','d']
>>> set(myList)
set(['a', 'c', 'b', 'd'])
Это лучше, если вам никогда не нужно хранить ценности, а просто хранить неупорядоченную коллекцию уникальных предметов.
Комментарии:
1. Плюс
set
потребляет меньше памяти (на один указатель меньше на элемент набора, или экономия 33%). Также проверьте постояннуюfrozenset
(неизменяемую) версию set. Нет никаких преимуществ в производительностиfrozenset
, но это делает логику программы более чистой.2. при поиске элемента в dict вам дается O(1) время доступа, в то время как упорядоченные наборы(по умолчанию) дают вам O(n), а упорядоченные наборы(те, которые у вас есть, например, дополнительные вычислительные затраты) дают вам O(logn).
Ответ №3:
Чтобы ответить на проблемы с производительностью исходного вопрошающего (для поиска в dict
vs set
), несколько удивительно, dict
что поиск может быть значительно быстрее (в Python 2.5.1 на моем довольно медленном ноутбуке), например, при условии, что половина поисков завершается неудачно, а половина-успешно. Вот как можно это выяснить:
$ python -mtimeit -s'k=dict.fromkeys(range(99))' '5 in k and 112 in k'
1000000 loops, best of 3: 0.236 usec per loop
$ python -mtimeit -s'k=set(range(99))' '5 in k and 112 in k'
1000000 loops, best of 3: 0.265 usec per loop
выполняйте каждую проверку несколько раз, чтобы убедиться, что они повторяемы. Итак, если эти 30 наносекунд или меньше на медленном ноутбуке являются абсолютно критическим узким местом, возможно, стоит выбрать неясное dict.fromkeys
решение, а не простое, очевидное, читаемое и четко правильное set
(необычно-почти всегда в Python простое и прямое решение также имеет преимущества в производительности).
Конечно, нужно свериться со своей собственной версией Python, машиной, данными и соотношением успешных и неудачных тестов и подтвердить с помощью чрезвычайно точного профилирования, что сокращение 30 наносекунд (или что-то еще) от этого поиска будет иметь важное значение.
К счастью, в подавляющем большинстве случаев это окажется совершенно ненужным… но поскольку программисты в любом случае будут зацикливаться на бессмысленных микрооптимизациях, независимо от того, сколько раз им говорят об их неуместности, timeit
модуль находится прямо в стандартной библиотеке, чтобы сделать эти в основном бессмысленные микро-тесты простыми, как пирог! -)
Комментарии:
1. Это потрясающий комментарий. Каждый разработчик одержим микрооптимизацией, которую необходимо выполнять, чтобы перечитывать ее снова и снова. Напоминает мне «(разворачивание дальнего цикла, для лучшей производительности)[ reddit.com/r/programming/comments/8ozon/… »
2. Не верно для (C)Python2.5: set быстрее как для сборки, так и для запроса
in
. Он также потребляет на 33% меньше памяти, о чем здесь еще не говорилось.
Ответ №4:
И вот довольно неправильный и неэффективный способ сделать это с помощью карты:
>>> d = dict()
>>> map (lambda x: d.__setitem__(x, None), [1,2,3])
[None, None, None]
>>> d
{1: None, 2: None, 3: None}
Ответ №5:
Вы можете использовать понимание списка:
my_list = ['a','b','c','d']
my_dict = dict([(ele, None) for ele in my_list])
Комментарии:
1. Вы также можете использовать понимание генератора (просто опустите квадратные скобки!) В Python 3.0 есть даже понимание диктантов
Ответ №6:
Может быть, вы можете использовать itertools:
>>>import itertools
>>>my_list = ['a','b','c','d']
>>>d = {}
>>>for x in itertools.imap(d.setdefault, my_list): pass
>>>print d
{'a': None, 'c': None, 'b': None, 'd': None}
Для огромных списков, возможно, это очень хорошо 😛
Комментарии:
1. Совет: выделите свой код и нажмите ctrl-k, чтобы получить подсветку синтаксиса и сохранить правильный отступ.