Как преобразовать два списка в словарь?

Представьте, что у вас есть следующий список.

keys = ['name', 'age', 'food']
values = ['Monty', 42, 'spam']

Как проще всего составить следующий словарь?

a_dict = {'name': 'Monty', 'age': 42, 'food': 'spam'}
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1 398
0
972 470
19
Перейти к ответу Данный вопрос помечен как решенный

Ответы 19

Ответ принят как подходящий

Нравится:

keys = ['a', 'b', 'c']
values = [1, 2, 3]
dictionary = dict(zip(keys, values))
print(dictionary) # {'a': 1, 'b': 2, 'c': 3}

Вуаля :-) Попарный конструктор dict и функция zip очень полезны.

Стоит отметить, что dictionary = {zip(keys, values)} работать не будет. Вы должны явно указать как dict(...)

Fernando Wittmann 28.08.2019 18:52

Не уверен, почему вы этого ожидали, @FernandoWittmann. {thing} - это синтаксический сахар для создания set(), содержащего один элемент. {*iterable} - это синтаксический сахар для создания set, содержащего несколько элементов. {k:v} или {**mapping}воля создают dict, но это синтаксически совершенно различно.

Dan Lenski 28.08.2019 19:41

Спасибо за комментарий, Дэн. Ты прав. Моя путаница произошла из-за того, что я обычно использую sintax {} для словарей. Фактически, если мы попробуем type({}), мы получим dict. Но действительно, если мы попробуем type({thing}), то на выходе получится set.

Fernando Wittmann 28.08.2019 20:42

Я приехал сюда на случай, если у нас получится лучше, чем {k:v for k, v in zip(keys, values)}. Оказывается, можем. +1.

J.G. 23.01.2020 17:28

@FernandoWittmann, вы правы, что это сбивает с толку. {[thing1, thing2, … thingN]} создает набор для любого значения N != 0; но для N == 0 он создает пустой dict, и вам нужно выполнить set(), чтобы создать пустой набор. Это несколько прискорбная и нарушающая PoLS бородавка Python из-за того, что в Python были литералы dict задолго до литералов set.

Dan Lenski 29.10.2020 03:14

цель сохранения кортежа zip-списка в качестве словаря - удалить повторяющийся аспект zip. zip возвращает итерируемые кортежи.

Golden Lion 05.11.2020 15:49

>>> 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.

Pedro Cattori 17.02.2017 17:56

Если вам нужно преобразовать ключи или значения перед созданием словаря, можно использовать генератор выражения. Пример:

>>> 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çois Fabre 13.09.2017 14:49

@ Jean-FrançoisFabre Это действительно важно? по какой причине мы должны создать два списка разной длины, чтобы построить словарь?

loved.by.Jesus 18.12.2019 01:35

вероятно нет, но после этого for n in range(len(List1)) будет анти-паттерном

Jean-François Fabre 18.12.2019 15:41

с 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, почему это так? Спасибо, чувак.

Haritsinh Gohil 08.08.2019 11:24

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 с zip

new_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)}

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')]

а 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)) выигрывает даже с небольшими наборами ключей и значений, но для больших наборов разница в производительности станет больше.

Комментатор сказал:

min seems like a bad way to compare performance. Surely mean and/or max would 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 dict call 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.

Mark_Anderson 02.07.2019 18:06

Кажется, вы говорите, что понимание dict происходит быстрее всего, но тогда в обзоре производительности dict(zip(keys, values)) выглядит быстрее. Может ты что то забыл обновить?

Loisaida Sam Sandberg 08.04.2020 05:57

Незначительное примечание (в значительной степени не относящееся к Python 2 EOL): вы можете использовать from future_builtins import zip в качестве альтернативы from itertools import izip as zip, что немного более четко описывает импорт с точки зрения получения Python 3 zip в качестве замены обычного zip. Это в точности эквивалентно тому, чтобы быть ясным (future_builtins.zip сам по себе просто псевдоним itertools.izip).

ShadowRanger 29.10.2020 21:24

метод без функции 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'}

Nursnaaz 31.01.2019 11:32

вы можете использовать этот код ниже:

dict(zip(['name', 'age', 'food'], ['Monty', 42, 'spam']))

Но убедитесь, что длина списков будет одинаковой. Если длина не одинакова, то функция zip поворачивает более длинный.

  • 2018-04-18

Лучшее решение по-прежнему:

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'}

Другие вопросы по теме