Представьте, что у вас есть следующий список.
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 и функция zip очень полезны.
Не уверен, почему вы этого ожидали, @FernandoWittmann. {thing} - это синтаксический сахар для создания set(), содержащего один элемент. {*iterable} - это синтаксический сахар для создания set, содержащего несколько элементов. {k:v} или {**mapping}воля создают dict, но это синтаксически совершенно различно.
Спасибо за комментарий, Дэн. Ты прав. Моя путаница произошла из-за того, что я обычно использую sintax {} для словарей. Фактически, если мы попробуем type({}), мы получим dict. Но действительно, если мы попробуем type({thing}), то на выходе получится set.
Я приехал сюда на случай, если у нас получится лучше, чем {k:v for k, v in zip(keys, values)}. Оказывается, можем. +1.
@FernandoWittmann, вы правы, что это сбивает с толку. {[thing1, thing2, … thingN]} создает набор для любого значения N != 0; но для N == 0 он создает пустой dict, и вам нужно выполнить set(), чтобы создать пустой набор. Это несколько прискорбная и нарушающая PoLS бородавка Python из-за того, что в Python были литералы dict задолго до литералов set.
цель сохранения кортежа zip-списка в качестве словаря - удалить повторяющийся аспект zip. zip возвращает итерируемые кортежи.
>>> keys = ('name', 'age', 'food')
>>> values = ('Monty', 42, 'spam')
>>> dict(zip(keys, values))
{'food': 'spam', 'age': 42, 'name': 'Monty'}
Попробуй это:
>>> 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.
Верно для Python2, но в Python 3 zip уже экономичен в потреблении памяти. docs.python.org/3/library/functions.html#zip Фактически, вы можете видеть, что six использует zip в Python 3 для замены itertools.izip в Python 2 pythonhosted.org/six.
Если вам нужно преобразовать ключи или значения перед созданием словаря, можно использовать генератор выражения. Пример:
>>> adict = dict((str(k), v) for k, v in zip(['a', 1, 'b'], [2, 'c', 3]))
Взгляните Код как Pythonista: идиоматический Python.
Вы также можете использовать словарные выражения в 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:
List1 = ['This', 'is', 'a', 'list']
List2 = ['Put', 'this', 'into', 'dictionary']
Это можно сделать одной строкой кода:
d = {List1[n]: List2[n] for n in range(len(List1))}
громко выходит из строя, если List1 длиннее List2
@ Jean-FrançoisFabre Это действительно важно? по какой причине мы должны создать два списка разной длины, чтобы построить словарь?
вероятно нет, но после этого for n in range(len(List1)) будет анти-паттерном
с Python 3.x подходит для понимания dict
keys = ('name', 'age', 'food')
values = ('Monty', 42, 'spam')
dic = {k:v for k,v in zip(keys, values)}
print(dic)
Подробнее о dict понимания здесь, пример есть:
>>> print {i : chr(65+i) for i in range(4)}
{0 : 'A', 1 : 'B', 2 : 'C', 3 : 'D'}
Более естественный способ - использовать понимание словаря
keys = ('name', 'age', 'food')
values = ('Monty', 42, 'spam')
dict = {keys[i]: values[i] for i in range(len(keys))}
иногда это самый быстрый способ, а иногда и самый медленный для преобразования в объект dict, почему это так? Спасибо, чувак.
Imagine that you have:
keys = ('name', 'age', 'food') values = ('Monty', 42, 'spam')What is the simplest way to produce the following dictionary ?
dict = {'name' : 'Monty', 'age' : 42, 'food' : 'spam'}
dict с zipnew_dict = dict(zip(keys, values))
В Python 3 zip теперь возвращает ленивый итератор, и теперь это наиболее производительный подход.
dict(zip(keys, values)) требует единовременного глобального поиска для dict и zip, но он не формирует ненужных промежуточных структур данных и не имеет дело с локальным поиском в приложении-функции.
Близким к использованию конструктора 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)}
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')]
а zip в Python 3 просто создает повторяющийся объект:
>>> 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)) выигрывает даже с небольшими наборами ключей и значений, но для больших наборов разница в производительности станет больше.
Комментатор сказал:
minseems like a bad way to compare performance. Surelymeanand/ormaxwould be much more useful indicators for real usage.
Мы используем min, потому что эти алгоритмы детерминированы. Мы хотим знать производительность алгоритмов в наилучших возможных условиях.
Если операционная система зависает по какой-либо причине, это не имеет никакого отношения к тому, что мы пытаемся сравнить, поэтому нам нужно исключить такие результаты из нашего анализа.
Если бы мы использовали mean, такие события сильно исказили бы наши результаты, а если бы мы использовали max, мы получили бы только самый экстремальный результат - тот, на который, скорее всего, повлияет такое событие.
Комментатор также говорит:
In python 3.6.8, using mean values, the dict comprehension is indeed still faster, by about 30% for these small lists. For larger lists (10k random numbers), the
dictcall is about 10% faster.
Я полагаю, мы имеем в виду dict(zip(... с 10 тысячами случайных чисел. Это действительно звучит как довольно необычный вариант использования. Имеет смысл, что самые прямые вызовы будут доминировать в больших наборах данных, и я не удивлюсь, если зависания ОС будут доминировать, учитывая, сколько времени потребуется для запуска этого теста, что еще больше искажает ваши цифры. А если вы используете 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
По состоянию на середину 2019 года (python 3.7.3) я обнаружил разные тайминги. %% timeit возвращает 1,57 \ pm 0,019 мкс для dict(zip(headList, textList)) и 1,95 \ pm 0,030 мкс для {k: v for k, v in zip(headList, textList)}. Я бы посоветовал первое для удобочитаемости и скорости. Очевидно, это происходит в аргументе min () vs mean () для timeit.
Кажется, вы говорите, что понимание dict происходит быстрее всего, но тогда в обзоре производительности dict(zip(keys, values)) выглядит быстрее. Может ты что то забыл обновить?
Незначительное примечание (в значительной степени не относящееся к Python 2 EOL): вы можете использовать from future_builtins import zip в качестве альтернативы from itertools import izip as zip, что немного более четко описывает импорт с точки зрения получения Python 3 zip в качестве замены обычного zip. Это в точности эквивалентно тому, чтобы быть ясным (future_builtins.zip сам по себе просто псевдоним itertools.izip).
метод без функции 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'}
Привет, xiyurui, вход (l1 и l2) должен быть списком. Если вы назначите l1 и l2 как набор, он может не сохранить порядок вставки. для меня я получил результат как {1: 'a', 2: 'c', 3: 'd', 4: 'b', 5: 'e'}
вы можете использовать этот код ниже:
dict(zip(['name', 'age', 'food'], ['Monty', 42, 'spam']))
Но убедитесь, что длина списков будет одинаковой. Если длина не одинакова, то функция zip поворачивает более длинный.
Лучшее решение по-прежнему:
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')
Вот также пример добавления значения списка в ваш словарь
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]
Вы также можете попробовать один список, который представляет собой комбинацию двух списков;)
a = [1,2,3,4]
n = [5,6,7,8]
x = []
for i in a,n:
x.append(i)
print(dict(zip(x[0], x[1])))
Хотя есть несколько способов сделать это, но я считаю наиболее фундаментальным подходом к этому; создание цикла и словаря и сохранение значений в этом словаре. В рекурсивном подходе идея все та же, но вместо использования цикла функция вызывала сама себя, пока не дойдет до конца. Конечно, есть и другие подходы, например, использование 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'}
Если вы работаете с более чем 1 набором значений и хотите иметь список изречений, вы можете использовать это:
def as_dict_list(data: list, columns: list):
return [dict((zip(columns, row))) for row in data]
Пример из реальной жизни - это список кортежей из запроса к базе данных в паре с кортежем столбцов из того же запроса. Остальные ответы предоставлены только 1 к 1.
keys = ['name', 'age', 'food']
values = ['Monty', 42, 'spam']
dic = {}
c = 0
for i in keys:
dic[i] = values[c]
c += 1
print(dic)
{'name': 'Monty', 'age': 42, 'food': 'spam'}
Стоит отметить, что
dictionary = {zip(keys, values)}работать не будет. Вы должны явно указать какdict(...)