Ubah dua daftar menjadi kamus

1229

Bayangkan Anda memiliki:

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

Apa cara paling sederhana untuk menghasilkan kamus berikut?

a_dict = {'name' : 'Monty', 'age' : 42, 'food' : 'spam'}
Guido
sumber

Jawaban:

2145

Seperti ini:

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

Voila :-) dictKonstruktor dan zipfungsi berpasangan sangat berguna: https://docs.python.org/3/library/functions.html#func-dict

Dan Lenski
sumber
3
Perlu dicatat bahwa dictionary = {zip(keys, values)}itu tidak akan berhasil. Anda harus secara eksplisit mendeklarasikan sebagaidict(...)
Fernando Wittmann
5
Tidak yakin mengapa Anda mengharapkannya, @FernandoWittmann. {thing}adalah gula sintaksis untuk membangun set()unsur yang mengandung satu. {*iterable}adalah gula sintaksis untuk membangun setbeberapa elemen yang mengandung. {k:v}atau {**mapping} akan membangun dict, tapi itu secara sintaksis sangat berbeda.
Dan Lenski
6
Terima kasih atas komentar Dan. Kamu benar. Kebingungan saya terjadi karena saya biasanya menggunakan sintax {}untuk kamus. Padahal, jika kita coba type({})outputnya adalah dict. Tapi memang, jika kita coba type({thing})maka outputnya adalah set.
Fernando Wittmann
Saya datang ke sini kalau-kalau kita bisa melakukan lebih baik daripada {k:v for k, v in zip(keys, values)}. Ternyata kita bisa. +1.
JG
140

Bayangkan Anda memiliki:

keys = ('name', 'age', 'food')
values = ('Monty', 42, 'spam')

Apa cara paling sederhana untuk menghasilkan kamus berikut?

dict = {'name' : 'Monty', 'age' : 42, 'food' : 'spam'}

Kebanyakan berkinerja, dictdengan konstruktorzip

new_dict = dict(zip(keys, values))

Dalam Python 3, zip sekarang mengembalikan iterator malas, dan sekarang ini adalah pendekatan yang paling performan.

dict(zip(keys, values))memang membutuhkan pencarian global satu kali untuk masing-masing dictdan zip, tetapi tidak membentuk struktur data menengah yang tidak perlu atau harus berurusan dengan pencarian lokal dalam aplikasi fungsi.

Runner-up, pemahaman dict:

Runner-up yang dekat untuk menggunakan konstruktor dict adalah dengan menggunakan sintaks asli dari pemahaman dict (bukan pemahaman daftar , seperti yang orang lain katakan secara keliru):

new_dict = {k: v for k, v in zip(keys, values)}

Pilih ini saat Anda perlu memetakan atau memfilter berdasarkan kunci atau nilai.

Dalam Python 2, zipmengembalikan daftar, untuk menghindari membuat daftar yang tidak perlu, gunakan izipsebagai gantinya (alias zip dapat mengurangi perubahan kode ketika Anda pindah ke Python 3).

from itertools import izip as zip

Jadi itu masih (2.7):

new_dict = {k: v for k, v in zip(keys, values)}

Python 2, ideal untuk <= 2.6

izipdari itertoolsmenjadi zipdi Python 3. iziplebih baik daripada zip untuk Python 2 (karena menghindari pembuatan daftar yang tidak perlu), dan ideal untuk 2.6 atau di bawah:

from itertools import izip
new_dict = dict(izip(keys, values))

Hasil untuk semua kasus:

Dalam semua kasus:

>>> new_dict
{'age': 42, 'name': 'Monty', 'food': 'spam'}

Penjelasan:

Jika kita melihat bantuan pada dictkita melihat bahwa dibutuhkan berbagai bentuk argumen:


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

Pendekatan optimal adalah dengan menggunakan iterable sambil menghindari membuat struktur data yang tidak perlu. Di Python 2, zip membuat daftar yang tidak perlu:

>>> zip(keys, values)
[('name', 'Monty'), ('age', 42), ('food', 'spam')]

Dalam Python 3, yang sederajat adalah:

>>> list(zip(keys, values))
[('name', 'Monty'), ('age', 42), ('food', 'spam')]

dan Python 3 ziphanya menciptakan objek yang dapat diubah:

>>> zip(keys, values)
<zip object at 0x7f0e2ad029c8>

Karena kami ingin menghindari membuat struktur data yang tidak perlu, kami biasanya ingin menghindari Python 2 zip(karena membuat daftar yang tidak perlu).

Alternatif yang kurang berkinerja:

Ini adalah ekspresi generator yang diteruskan ke konstruktor dikt:

generator_expression = ((k, v) for k, v in zip(keys, values))
dict(generator_expression)

atau yang setara:

dict((k, v) for k, v in zip(keys, values))

Dan ini adalah daftar pemahaman yang diteruskan ke konstruktor dikt:

dict([(k, v) for k, v in zip(keys, values)])

Dalam dua kasus pertama, lapisan tambahan dari perhitungan non-operasi (dengan demikian tidak perlu) ditempatkan di atas zip iterable, dan dalam hal pemahaman daftar, daftar tambahan tidak perlu dibuat. Saya berharap mereka semua menjadi kurang performan, dan tentu saja tidak lebih.

Ulasan kinerja:

Dalam 64 bit Python 3.8.2 disediakan oleh Nix, di Ubuntu 16.04, dipesan dari yang tercepat hingga yang paling lambat:

>>> 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)) menang bahkan dengan set kunci dan nilai yang kecil, tetapi untuk set yang lebih besar, perbedaan dalam kinerja akan menjadi lebih besar.

Seorang komentator berkata:

minSepertinya cara yang buruk untuk membandingkan kinerja. Tentunya meandan / atau maxakan menjadi indikator yang jauh lebih berguna untuk penggunaan nyata.

Kami menggunakan minkarena algoritma ini bersifat deterministik. Kami ingin mengetahui kinerja algoritma dalam kondisi terbaik.

Jika sistem operasi hang untuk alasan apa pun, itu tidak ada hubungannya dengan apa yang kami coba bandingkan, jadi kami perlu mengecualikan hasil semacam itu dari analisis kami.

Jika kita menggunakan mean, peristiwa semacam itu akan sangat maxmemengaruhi hasil kita, dan jika kita menggunakan kita hanya akan mendapatkan hasil yang paling ekstrim - yang kemungkinan besar dipengaruhi oleh peristiwa semacam itu.

Seorang komentator juga mengatakan:

Dalam python 3.6.8, menggunakan nilai rata-rata, pemahaman dict memang masih lebih cepat, sekitar 30% untuk daftar kecil ini. Untuk daftar yang lebih besar (10k angka acak), dictpanggilan ini sekitar 10% lebih cepat.

Saya kira kita maksud dict(zip(...dengan angka acak 10k. Itu terdengar seperti kasus penggunaan yang tidak biasa. Masuk akal bahwa panggilan paling langsung akan mendominasi dalam dataset besar, dan saya tidak akan terkejut jika OS hang mendominasi mengingat berapa lama waktu yang dibutuhkan untuk menjalankan tes itu, lebih lanjut condong angka Anda. Dan jika Anda menggunakan meanatau maxsaya akan menganggap hasil Anda tidak berarti.

Mari kita gunakan ukuran yang lebih realistis pada contoh teratas kami:

import numpy
import timeit
l1 = list(numpy.random.random(100))
l2 = list(numpy.random.random(100))

Dan kita lihat di sini bahwa dict(zip(...memang berjalan lebih cepat untuk kumpulan data yang lebih besar sekitar 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
Aaron Hall
sumber
1
Pada pertengahan 2019 (python 3.7.3), saya menemukan timing yang berbeda. %% timeit mengembalikan 1,57 \ pm 0,019 mikro untuk dict(zip(headList, textList))& 1,95 \ pm 0,030 mikro untuk {k: v for k, v in zip(headList, textList)}. Saya akan menyarankan yang pertama untuk keterbacaan dan kecepatan. Jelas ini menjadi argumen min () vs mean () untuk timeit.
Mark_Anderson
1
minSepertinya cara yang buruk untuk membandingkan kinerja. Tentunya meandan / atau maxakan menjadi indikator yang jauh lebih berguna untuk penggunaan nyata.
naught101
1
Dalam python 3.6.8, menggunakan nilai rata-rata, pemahaman dict memang masih lebih cepat, sekitar 30% untuk daftar kecil ini. Untuk daftar yang lebih besar (10k angka acak), dictpanggilan ini sekitar 10% lebih cepat.
nucky101
@ naught101 - Saya menjawab komentar Anda dalam jawaban saya.
Aaron Hall
3
Angka 10k hanyalah cara cepat untuk menghasilkan 2 daftar panjang elemen unik. Pembuatan daftar dilakukan di luar perkiraan waktu. // Kenapa menurutmu mean atau max tidak berguna? Jika Anda melakukan ini berkali-kali, maka waktu rata-rata Anda adalah ~ n * rata-rata, dan dibatasi oleh ~ n * maks. Minimum Anda memberikan batas yang lebih rendah, tetapi kebanyakan orang peduli dengan kinerja rata-rata atau terburuk. Jika ada varian tinggi, minimum Anda akan sepenuhnya tidak mewakili sebagian besar kasus. Bagaimana minimum lebih bermakna dalam skenario dunia nyata?
nucky101
128

Coba ini:

>>> import itertools
>>> keys = ('name', 'age', 'food')
>>> values = ('Monty', 42, 'spam')
>>> adict = dict(itertools.izip(keys,values))
>>> adict
{'food': 'spam', 'age': 42, 'name': 'Monty'}

Dalam Python 2, itu juga lebih ekonomis dalam konsumsi memori dibandingkan dengan zip.

Mike Davis
sumber
18
Benar untuk Python2, tetapi dalam Python 3, zipsudah ekonomis dalam konsumsi memori. docs.python.org/3/library/functions.html#zip Bahkan, Anda dapat melihat bahwa sixmenggunakan zipPython 3 untuk menggantikan itertools.izipPython 2 pythonhosted.org/six .
Pedro Cattori
35
>>> keys = ('name', 'age', 'food')
>>> values = ('Monty', 42, 'spam')
>>> dict(zip(keys, values))
{'food': 'spam', 'age': 42, 'name': 'Monty'}
iny
sumber
28

Anda juga dapat menggunakan pemahaman kamus dengan 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'}
Brendan Berg
sumber
17

Cara yang lebih alami adalah dengan menggunakan pemahaman kamus

keys = ('name', 'age', 'food')
values = ('Monty', 42, 'spam')    
dict = {keys[i]: values[i] for i in range(len(keys))}
Polla A. Fattah
sumber
kadang itu cara tercepat dan kadang paling lambat untuk mengkonversi ke dictobjek, mengapa begitu?, terima kasih Bung.
Haritsinh Gohil
10

dengan Python 3.x, berlaku untuk pemahaman dict

keys = ('name', 'age', 'food')
values = ('Monty', 42, 'spam')

dic = {k:v for k,v in zip(keys, values)}

print(dic)

Lebih lanjut tentang pemahaman dikt di sini , contoh ada di sana:

>>> print {i : chr(65+i) for i in range(4)}
    {0 : 'A', 1 : 'B', 2 : 'C', 3 : 'D'}
Kiriloff
sumber
8

Bagi mereka yang membutuhkan kode sederhana dan tidak terbiasa dengan zip:

List1 = ['This', 'is', 'a', 'list']
List2 = ['Put', 'this', 'into', 'dictionary']

Ini dapat dilakukan dengan satu baris kode:

d = {List1[n]: List2[n] for n in range(len(List1))}
exploitprotocol
sumber
6
gagal dengan keras jika List1lebih lama dariList2
Jean-François Fabre
@ Jean-FrançoisFabre Apakah ini penting? Apa alasan kami harus memilih dua daftar dengan panjang yang berbeda untuk membuat kamus?
loved.by.Yesus
mungkin tidak, tetapi setelah ini for n in range(len(List1))merupakan anti-pola
Jean-François Fabre
3
  • 2018-04-18

Solusi terbaik masih:

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

Tranpose itu:

    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')
Kalkulus
sumber
2

Anda dapat menggunakan kode di bawah ini:

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

Tetapi pastikan bahwa panjang daftar akan sama. Jika panjangnya tidak sama, maka fungsi zip akan lebih panjang.

Akash Nayak
sumber
2

Saya memiliki keraguan ini ketika saya mencoba untuk menyelesaikan masalah yang berhubungan dengan grafik. Masalah yang saya miliki adalah saya perlu mendefinisikan daftar adjacency kosong dan ingin menginisialisasi semua node dengan daftar kosong, saat itulah saya berpikir bagaimana kalau saya periksa apakah cukup cepat, maksud saya jika layak melakukan operasi zip daripada pasangan nilai kunci penugasan sederhana. Bagaimanapun juga, faktor waktu adalah pemecah es yang penting. Jadi saya melakukan operasi timeit untuk kedua pendekatan.

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

Untuk n_nodes = 10.000.000 saya dapatkan,

Iterasi: 2.825081646999024 Singkatan: 3.535717916001886

Iterasi: 5.051560923002398 Singkatan: 6.255070794999483

Iterasi: 6.52859034499852 Singkatan: 8.221581164998497

Iterasi: 8.683652416999394 Singkatan: 12.599181543999293

Iterasi: 11.587241565001023 Singkatan: 15.27298851100204

Iterasi: 14.816342867001367 Singkatan: 17.162912737003353

Iterasi: 16.645022411001264 Singkatan: 19.976680120998935

Anda dapat melihat dengan jelas setelah titik tertentu, pendekatan iterasi pada langkah n_th mengambil alih waktu yang diambil oleh pendekatan steno pada langkah n-1_th.

Mayank Prakash
sumber
1

Ini juga contoh menambahkan nilai daftar di kamus Anda

list1 = ["Name", "Surname", "Age"]
list2 = [["Cyd", "JEDD", "JESS"], ["DEY", "AUDIJE", "PONGARON"], [21, 32, 47]]
dic = dict(zip(list1, list2))
print(dic)

selalu pastikan "Kunci" Anda (list1) selalu di parameter pertama.

{'Name': ['Cyd', 'JEDD', 'JESS'], 'Surname': ['DEY', 'AUDIJE', 'PONGARON'], 'Age': [21, 32, 47]}
Cyd
sumber
0

Solusi sebagai pemahaman kamus dengan menyebutkan:

dict = {item : values[index] for index, item in enumerate(keys)}

Solusi untuk loop dengan penghitungan:

dict = {}
for index, item in enumerate(keys):
    dict[item] = values[index]
jay123
sumber
0

Anda juga dapat mencoba dengan satu daftar yang merupakan kombinasi dari dua daftar;)

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])))
Lakhan Ramawat
sumber
-1

metode tanpa fungsi 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
sumber
Hai xiyurui, Input (l1 dan l2) harus berupa daftar. Jika Anda menetapkan l1 dan l2 sebagai set, itu mungkin tidak mempertahankan urutan penyisipan. bagi saya, saya mendapatkan output sebagai {1: 'a', 2: 'c', 3: 'd', 4: 'b', 5: 'e'}
Nursnaaz