Представьте, что у вас есть следующий список.
keys = ['name', 'age', 'food']
values = ['Monty', 42, 'spam']
Как проще всего составить следующий словарь?
a_dict = {'name': 'Monty', 'age': 42, 'food': 'spam'}
Представьте, что у вас есть следующий список.
keys = ['name', 'age', 'food']
values = ['Monty', 42, 'spam']
Как проще всего составить следующий словарь?
a_dict = {'name': 'Monty', 'age': 42, 'food': 'spam'}
Нравится:
keys = ['a', 'b', 'c']
values = [1, 2, 3]
dictionary = dict(zip(keys, values))
print(dictionary) # {'a': 1, 'b': 2, 'c': 3}
Вуаля :-) Попарный конструктор dict
и _ 3_ чрезвычайно полезна.
dictionary = {zip(keys, values)}
не сработает. Вы должны явно указать как dict(...)
- person Fernando Wittmann; 28.08.2019
{thing}
- это синтаксический сахар для создания set()
, содержащего один элемент. {*iterable}
- это синтаксический сахар для создания set
, содержащего несколько элементов. {k:v}
или {**mapping}
будет построить dict
, но это синтаксически совершенно различно.
- person Dan Lenski; 28.08.2019
{}
для словарей. Фактически, если мы попробуем type({})
, результат будет dict
. Но действительно, если мы попробуем type({thing})
, то на выходе будет set
.
- person Fernando Wittmann; 28.08.2019
{k:v for k, v in zip(keys, values)}
. Оказывается, можем. +1.
- person J.G.; 23.01.2020
{[thing1, thing2, … thingN]}
создает набор для любого значения N != 0
; но для N == 0
он создает пустой dict
, и вам нужно сделать set()
, чтобы создать пустой набор. Это несколько прискорбно и PoLS нарушает Python из-за того, что Python dict
-литералы были задолго до set
-литералов.
- person Dan Lenski; 29.10.2020
Представьте, что у вас есть:
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 (а не понимания list, как ошибочно выразились другие):
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)}
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>
Поскольку мы хотим избежать создания ненужных структур данных, мы обычно хотим избегать 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:
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
dict(zip(headList, textList))
и 1,95 \ pm 0,030 мкс для {k: v for k, v in zip(headList, textList)}
. Я бы посоветовал первое для удобочитаемости и скорости. Очевидно, это происходит в аргументе min () vs mean () для timeit.
- person Mark_Anderson; 02.07.2019
dict(zip(keys, values))
выглядит быстрее. Может ты что то забыл обновить?
- person Loisaida Sam Sandberg; 08.04.2020
from future_builtins import zip
в качестве альтернативы from itertools import izip as zip
, что немного более четко описывает импорт с точки зрения получения Python 3 zip
в качестве замены обычного zip
. Это в точности эквивалентно тому, чтобы быть ясным (future_builtins.zip
сам по себе просто псевдоним itertools.izip
).
- person ShadowRanger; 29.10.2020
Попробуй это:
>>> 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
уже экономно расходует память. docs.python.org/3/library/functions.html#zip Фактически, вы можете видеть, что six
использует zip
в Python 3 для замены itertools.izip
в Python 2 pythonhosted.org/six а>.
- person Pedro Cattori; 17.02.2017
Вы также можете использовать словарные выражения в 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'}
Более естественный способ - использовать понимание словаря
keys = ('name', 'age', 'food')
values = ('Monty', 42, 'spam')
dict = {keys[i]: values[i] for i in range(len(keys))}
dict
, почему это так? Спасибо, чувак.
- person Haritsinh Gohil; 08.08.2019
Если вам нужно преобразовать ключи или значения перед созданием словаря, можно использовать выражение-генератор. . Пример:
>>> adict = dict((str(k), v) for k, v in zip(['a', 1, 'b'], [2, 'c', 3]))
Взгляните на Код как Pythonista: Идиоматический Python.
с Python 3.x подходит для понимания dict
keys = ('name', 'age', 'food')
values = ('Monty', 42, 'spam')
dic = {k:v for k,v in zip(keys, values)}
print(dic)
Подробнее о словах здесь, есть пример:
>>> print {i : chr(65+i) for i in range(4)}
{0 : 'A', 1 : 'B', 2 : 'C', 3 : 'D'}
Для тех, кому нужен простой код и не знаком с zip
:
List1 = ['This', 'is', 'a', 'list']
List2 = ['Put', 'this', 'into', 'dictionary']
Это можно сделать одной строкой кода:
d = {List1[n]: List2[n] for n in range(len(List1))}
List1
длиннее List2
- person Jean-François Fabre; 13.09.2017
for n in range(len(List1))
- анти-паттерн
- person Jean-François Fabre; 18.12.2019
Лучшее решение по-прежнему:
In [92]: keys = ('name', 'age', 'food')
...: values = ('Monty', 42, 'spam')
...:
In [93]: dt = dict(zip(keys, values))
In [94]: dt
Out[94]: {'age': 42, 'food': 'spam', 'name': 'Monty'}
Транспонируйте это:
lst = [('name', 'Monty'), ('age', 42), ('food', 'spam')]
keys, values = zip(*lst)
In [101]: keys
Out[101]: ('name', 'age', 'food')
In [102]: values
Out[102]: ('Monty', 42, 'spam')
вы можете использовать этот код ниже:
dict(zip(['name', 'age', 'food'], ['Monty', 42, 'spam']))
Но убедитесь, что длина списков будет одинаковой. Если длина не одинакова, то функция zip поворачивает более длинный.
Вот также пример добавления значения списка в ваш словарь.
list1 = ["Name", "Surname", "Age"]
list2 = [["Cyd", "JEDD", "JESS"], ["DEY", "AUDIJE", "PONGARON"], [21, 32, 47]]
dic = dict(zip(list1, list2))
print(dic)
всегда убедитесь, что ваш «Ключ» (list1) всегда находится в первом параметре.
{'Name': ['Cyd', 'JEDD', 'JESS'], 'Surname': ['DEY', 'AUDIJE', 'PONGARON'], 'Age': [21, 32, 47]}
У меня было это сомнение, когда я пытался решить проблему, связанную с графом. Проблема, с которой я столкнулся, заключалась в том, что мне нужно было определить пустой список смежности и я хотел инициализировать все узлы с пустым списком, тогда я подумал, как насчет того, чтобы проверить, достаточно ли он быстр, я имею в виду, стоит ли выполнять операцию zip вместо простой пары "ключ-значение" присваивания. В конце концов, в большинстве случаев фактор времени является важным ледоколом. Итак, я выполнил операцию timeit для обоих подходов.
import timeit
def dictionary_creation(n_nodes):
dummy_dict = dict()
for node in range(n_nodes):
dummy_dict[node] = []
return dummy_dict
def dictionary_creation_1(n_nodes):
keys = list(range(n_nodes))
values = [[] for i in range(n_nodes)]
graph = dict(zip(keys, values))
return graph
def wrapper(func, *args, **kwargs):
def wrapped():
return func(*args, **kwargs)
return wrapped
iteration = wrapper(dictionary_creation, n_nodes)
shorthand = wrapper(dictionary_creation_1, n_nodes)
for trail in range(1, 8):
print(f'Itertion: {timeit.timeit(iteration, number=trails)}\nShorthand: {timeit.timeit(shorthand, number=trails)}')
Для n_nodes = 10 000 000 я получаю,
Итерация: 2.825081646999024 В сокращении: 3.535717916001886
Итерация: 5.051560923002398 Сокращение: 6.255070794999483
Итерация: 6.52859034499852 Сокращение: 8.221581164998497
Итерация: 8.683652416999394 В сокращении: 12.599181543999293
Итерация: 11.587241565001023 В сокращении: 15.27298851100204
Итерация: 14.816342867001367 В сокращении: 17.162912737003353
Итерация: 16.645022411001264 В сокращении: 19.976680120998935
Вы можете ясно видеть, что после определенного момента итерационный подход на n_-м шаге обгоняет время, затрачиваемое на сокращенный подход на n-1_-м шаге.
Решение как понимание словаря с enumerate:
dict = {item : values[index] for index, item in enumerate(keys)}
Решение для цикла с перечислением:
dict = {}
for index, item in enumerate(keys):
dict[item] = values[index]
Если вы работаете с более чем одним набором значений и хотите иметь список словаря, вы можете использовать это:
def as_dict_list(data: list, columns: list):
return [dict((zip(columns, row))) for row in data]
Пример из реальной жизни - это список кортежей из запроса к базе данных в паре с кортежем столбцов из того же запроса. Остальные ответы предоставлены только 1 к 1.
метод без функции zip
l1 = [1,2,3,4,5]
l2 = ['a','b','c','d','e']
d1 = {}
for l1_ in l1:
for l2_ in l2:
d1[l1_] = l2_
l2.remove(l2_)
break
print (d1)
{1: 'd', 2: 'b', 3: 'e', 4: 'a', 5: 'c'}
Хотя есть несколько способов сделать это, но я считаю наиболее фундаментальным подходом к этому; создание цикла и словаря и сохранение значений в этом словаре. В рекурсивном подходе идея все та же, но вместо использования цикла функция вызывала себя, пока не дойдет до конца. Конечно, есть и другие подходы, такие как использование dict(zip(key, value))
и т. Д. Это не самые эффективные решения.
y = [1,2,3,4]
x = ["a","b","c","d"]
# This below is a brute force method
obj = {}
for i in range(len(y)):
obj[y[i]] = x[i]
print(obj)
# Recursive approach
obj = {}
def map_two_lists(a,b,j=0):
if j < len(a):
obj[b[j]] = a[j]
j +=1
map_two_lists(a, b, j)
return obj
res = map_two_lists(x,y)
print(res)
Оба результата должны напечатать
{1: 'a', 2: 'b', 3: 'c', 4: 'd'}