Создание словаря (dict) из отдельных списков ключей и значений
Я хочу объединить эти:
keys = ['name', 'age', 'food']
values = ['Monty', 42, 'spam']
в единый словарь:
{'name': 'Monty', 'age': 42, 'food': 'spam'}
Как я могу это сделать?
Переведено автоматически
Ответ 1
Вот так:
keys = ['a', 'b', 'c']
values = [1, 2, 3]
dictionary = dict(zip(keys, values))
print(dictionary) # {'a': 1, 'b': 2, 'c': 3}
Вуаля :-) Попарные dict
конструктор и zip
функция потрясающе полезны.
Ответ 2
Представьте, что у вас есть:
keys = ('name', 'age', 'food')
values = ('Monty', 42, 'spam')Какой самый простой способ создать следующий словарь?
dict = {'name' : 'Monty', 'age' : 42, 'food' : 'spam'}
Самый производительный, dict
конструктор с zip
new_dict = dict(zip(keys, values))
В Python 3 zip теперь возвращает отложенный итератор, и на данный момент это наиболее производительный подход.
dict(zip(keys, values))
требует одноразового глобального поиска каждого для dict
и zip
, но это не формирует никаких ненужных промежуточных структур данных и не требует локального поиска в приложении-функции.
Второе место, понимание dict:
Вторым шагом к использованию конструктора dict является использование собственного синтаксиса понимания dict (а не понимания списка, как ошибочно полагают другие).:
new_dict = {k: v for k, v in zip(keys, values)}
Выберите этот параметр, когда вам нужно сопоставить или отфильтровать на основе ключей или значения.
В Python 2 zip
возвращает список, чтобы избежать создания ненужного списка, используйте izip
вместо этого (псевдоним zip может уменьшить изменения кода при переходе на Python 3).
from itertools import izip as zip
Так что это все еще (2.7):
new_dict = {k: v for k, v in zip(keys, values)}
Python 2, идеально подходит для <= 2.6
izip
из itertools
становится zip
в Python 3. izip
лучше, чем zip для Python 2 (потому что это позволяет избежать ненужного создания списка), и идеально подходит для версии 2.6 или ниже:
from itertools import izip
new_dict = dict(izip(keys, values))
Результат для всех случаев:
Во всех случаях:
>>> new_dict
{'age': 42, 'name': 'Monty', 'food': 'spam'}
Объяснение:
Если мы посмотрим на справку по dict
, мы увидим, что он принимает различные формы аргументов:
>>> help(dict)
class dict(object)
| dict() -> new empty dictionary
| dict(mapping) -> new dictionary initialized from a mapping object's
| (key, value) pairs
| dict(iterable) -> new dictionary initialized as if via:
| d = {}
| for k, v in iterable:
| d[k] = v
| dict(**kwargs) -> new dictionary initialized with the name=value pairs
| in the keyword argument list. For example: dict(one=1, two=2)
Оптимальный подход заключается в использовании итерируемого, избегая при этом создания ненужных структур данных. В Python 2 zip создает ненужный список:
>>> zip(keys, values)
[('name', 'Monty'), ('age', 42), ('food', 'spam')]
В Python 3 эквивалентом будет:
>>> list(zip(keys, values))
[('name', 'Monty'), ('age', 42), ('food', 'spam')]
и Python 3 zip
просто создает итерируемый объект:
>>> zip(keys, values)
<zip object at 0x7f0e2ad029c8>
Поскольку мы хотим избежать создания ненужных структур данных, мы обычно хотим избегать Python 2 zip
(поскольку он создает ненужный список).
Менее производительные альтернативы:
Это выражение генератора, передаваемое конструктору dict:
generator_expression = ((k, v) for k, v in zip(keys, values))
dict(generator_expression)
или что-то подобное:
dict((k, v) for k, v in zip(keys, values))
И это понимание списка, передаваемое конструктору dict:
dict([(k, v) for k, v in zip(keys, values)])
В первых двух случаях дополнительный слой неоперативных (следовательно, ненужных) вычислений размещается поверх итерируемого zip, а в случае понимания списка дополнительный список создается без необходимости. Я бы ожидал, что все они будут менее производительными, и уж точно не более того.
Обзор производительности:
В 64-разрядном Python 3.8.2, предоставленном Nix, в Ubuntu 16.04 упорядочен от самого быстрого к самому медленному:
>>> min(timeit.repeat(lambda: dict(zip(keys, values))))
0.6695233230129816
>>> min(timeit.repeat(lambda: {k: v for k, v in zip(keys, values)}))
0.6941362579818815
>>> min(timeit.repeat(lambda: {keys[i]: values[i] for i in range(len(keys))}))
0.8782548159942962
>>>
>>> min(timeit.repeat(lambda: dict([(k, v) for k, v in zip(keys, values)])))
1.077607496001292
>>> min(timeit.repeat(lambda: dict((k, v) for k, v in zip(keys, values))))
1.1840861019445583
dict(zip(keys, values))
выигрывает даже с небольшими наборами ключей и значений, но для больших наборов разница в производительности станет больше.
Комментатор сказал:
min
кажется плохим способом сравнения производительности. Несомненно,mean
и / илиmax
были бы гораздо более полезными показателями для реального использования.
Мы используем min
, потому что эти алгоритмы детерминированы. Мы хотим знать производительность алгоритмов при наилучших возможных условиях.
Если операционная система зависает по какой-либо причине, это не имеет никакого отношения к тому, что мы пытаемся сравнить, поэтому нам нужно исключить такого рода результаты из нашего анализа.
Если бы мы использовали mean
, события такого рода сильно исказили бы наши результаты, а если бы мы использовали max
, мы получили бы только самый экстремальный результат - тот, на который, скорее всего, повлияет такое событие.
Комментатор также сообщает:
В python 3.6.8 с использованием средних значений понимание dict действительно происходит еще быстрее, примерно на 30% для этих небольших списков. Для больших списков (10k случайных чисел),
dict
вызов выполняется примерно на 10% быстрее.
Я полагаю, мы имеем в виду dict(zip(...
с 10k случайными числами. Это звучит как довольно необычный вариант использования. Имеет смысл, что самые прямые вызовы будут доминировать в больших наборах данных, и я не удивлюсь, если зависания ОС будут доминирующими, учитывая, сколько времени потребуется для запуска этого теста, что еще больше исказит ваши цифры. И если вы используете mean
или max
, я бы счел ваши результаты бессмысленными.
Давайте используем более реалистичный размер в наших лучших примерах:
import numpy
import timeit
l1 = list(numpy.random.random(100))
l2 = list(numpy.random.random(100))
И здесь мы видим, что dict(zip(...
действительно работает быстрее для больших наборов данных примерно на 20%.
>>> min(timeit.repeat(lambda: {k: v for k, v in zip(l1, l2)}))
9.698965263989521
>>> min(timeit.repeat(lambda: dict(zip(l1, l2))))
7.9965161079890095
Ответ 3
Попробуйте это:
>>> import itertools
>>> keys = ('name', 'age', 'food')
>>> values = ('Monty', 42, 'spam')
>>> adict = dict(itertools.izip(keys,values))
>>> adict
{'food': 'spam', 'age': 42, 'name': 'Monty'}
В Python 2 также более экономично расходуется память по сравнению с zip
.
Ответ 4
keys = ('name', 'age', 'food')
values = ('Monty', 42, 'spam')
out = dict(zip(keys, values))
Вывод:
{'food': 'spam', 'age': 42, 'name': 'Monty'}