Создание словаря (dict) из отдельных списков ключей и значений
Я пытаюсь объединить два списка в один словарь. У меня есть следующие данные:
keys = ['name', 'age', 'food']
values = ['Monty', 42, 'spam']
Я хотел бы получить результат в виде:
{'name': 'Monty', 'age': 42, 'food': 'spam'}
Как я могу это сделать?
5 ответ(ов)
Самый простой способ создать словарь на основе ваших ключей и значений — использовать конструктор dict
с функцией zip
. Вот пример:
keys = ('name', 'age', 'food')
values = ('Monty', 42, 'spam')
new_dict = dict(zip(keys, values))
В Python 3 функция zip
теперь возвращает «ленивый» итератор, что делает этот подход наиболее производительным. dict(zip(keys, values))
требует единовременной глобальной проверки для dict
и zip
, но при этом не создает ненужных промежуточных структур данных и не требует локальных проверок при применении функции.
Альтернатива — генератор словаря
Близким по производительности вариантом будет использование синтаксиса генератора словаря (не путать с генератором списка):
new_dict = {k: v for k, v in zip(keys, values)}
Этот способ стоит использовать, если вам необходимо преобразовать или отфильтровать данные на основе ключей или значений.
В Python 2 функция zip
возвращает список, поэтому чтобы избежать ненужного создания списка, используйте izip
:
from itertools import izip as zip
new_dict = {k: v for k, v in zip(keys, values)}
Для Python 2, для версий ⇐ 2.6
Функция izip
из модуля itertools
в Python 3 становится обычной zip
. Она лучше, чем zip
в Python 2, так как не создает лишний список.
from itertools import izip
new_dict = dict(izip(keys, values))
Результат для всех случаев:
В любом случае вы получите:
>>> new_dict
{'name': 'Monty', 'age': 42, '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')]
Тем не менее, zip
в Python 3 просто создает итератор:
>>> zip(keys, values)
<zip object at 0x7f0e2ad029c8>
Поскольку мы хотим избежать создания ненужных структур данных, обычно мы предпочитаем zip
в Python 3, а не zip
в Python 2 (так как он создает лишний список).
Менее производительные альтернативы:
Вы также можете использовать генераторное выражение для передачи в конструктор 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([(k, v) for k, v in zip(keys, values)])
В первых двух случаях создает дополнительный уровень ненужных вычислений, а в последнем — лишний список. Все эти варианты, скорее всего, будут менее производительными, чем использование dict(zip(keys, values))
.
Анализ производительности:
В Python 3.8.2, оценив производительность различных методов, можно сделать выводы:
>>> 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
для выбора производительности — это нормальная практика в анализе алгоритмов, так как мы хотим узнать производительность в наилучших условиях.
Попробуйте это:
>>> 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
.
В вашем коде вы создаете словарь, используя функцию zip
, которая принимает два итерируемых объекта — в данном случае, кортежи keys
и values
.
Вот пошаговое объяснение:
keys
— это кортеж, содержащий строки, которые будут использоваться в качестве ключей:('name', 'age', 'food')
.values
— это тоже кортеж, содержащий значения для соответствующих ключей:('Monty', 42, 'spam')
.- Функция
zip(keys, values)
объединяет элементы из обоих кортежей в пары, создавая итератор, в котором каждый элемент — это кортеж, содержащий ключ и значение. То есть, получится такой итератор:(('name', 'Monty'), ('age', 42), ('food', 'spam'))
. - Затем
dict()
создает словарь из этих пар.
В результате создается словарь, который будет выглядеть следующим образом:
{'food': 'spam', 'age': 42, 'name': 'Monty'}
Обратите внимание, что порядок ключей в словаре, как правило, не гарантируется, но с Python 3.7 и выше порядок сохранится как в исходных данных.
Вы также можете использовать выражения-генераторы для словарей в Python версии 2.7 и выше:
>>> keys = ('name', 'age', 'food')
>>> values = ('Monty', 42, 'spam')
>>> {k: v for k, v in zip(keys, values)}
{'food': 'spam', 'age': 42, 'name': 'Monty'}
В этом примере мы используем функцию zip
, чтобы объединить ключи и значения, а затем создаем словарь, перебирая пары ключ-значение, что позволяет получить желаемую структуру данных.
Более естественный способ — это использовать генератор словарей:
keys = ('name', 'age', 'food')
values = ('Monty', 42, 'spam')
result_dict = {keys[i]: values[i] for i in range(len(keys))}
В данном коде мы создаем словарь result_dict
, где ключи берутся из кортежа keys
, а значения — из кортежа values
. Использование генератора словаря позволяет сделать код более читаемым и избежать необходимости использования других конструкций, таких как цикл. Вместо этого можно использовать функцию zip()
для более краткой записи:
result_dict = dict(zip(keys, values))
Этот способ ещё более лаконичен и делает код чище.
Как отсортировать список словарей по значению словаря в Python?
Как вернуть ключи словаря в виде списка в Python?
Создание словаря с помощью генератора словарей
Как скопировать словарь и редактировать только копию
Найти значение в списке