İki listeyi sözlüğe dönüştürme


1228

Sahip olduğunuzu hayal edin:

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

Aşağıdaki sözlüğü oluşturmanın en basit yolu nedir?

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

Yanıtlar:


2143

Bunun gibi:

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

Voila :-) Çift dictyapıcı ve zipişlev çok faydalıdır: https://docs.python.org/3/library/functions.html#func-dict


3
İşe dictionary = {zip(keys, values)}yaramayacağını belirtmek gerekir . Açıkça ilan etmelisinizdict(...)
Fernando Wittmann

5
Neden beklediğinden emin değilim, @FernandoWittmann. bir element içeren bir {thing}sentetik şekerdir set(). birkaç element içeren {*iterable}bir sentetik şekerdir set. {k:v}ya {**mapping} da bir inşa edecekdict , ama bu sözdizimsel olarak oldukça farklı.
Dan Lenski

6
Yorum için teşekkürler Dan. Haklısın. Karışıklığım oldu, çünkü genellikle {}sözlükler için sintaks kullanıyorum . Aslında, denersek type({})çıktı olur dict. Ama gerçekten, eğer denersek, type({thing})çıktı olur set.
Fernando Wittmann

Daha iyisini yapabilmemiz için buraya geldim {k:v for k, v in zip(keys, values)}. Olabiliriz. +1.
JG

139

Sahip olduğunuzu hayal edin:

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

Aşağıdaki sözlüğü oluşturmanın en basit yolu nedir?

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

En performanslı, dictyapıcızip

new_dict = dict(zip(keys, values))

Python 3'te zip artık tembel bir yineleyici döndürüyor ve bu şimdi en performanslı yaklaşım.

dict(zip(keys, values))için bir defalık küresel arama her gerektirir dictve zipancak herhangi bir ara gereksiz veri yapıları oluşturmak veya fonksiyon uygulamasında yerel aramalar ile uğraşmak zorunda değildir.

İkincilik, diksiyon anlama:

Dict yapıcısını kullanmaya yakından bakan, bir dict kavramasının yerel sözdizimini kullanmaktır ( diğerleri yanlışlıkla koyduğu gibi bir liste kavrama değil):

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

Anahtarlara veya değere göre eşlemeniz veya filtrelemeniz gerektiğinde bunu seçin.

Python 2'de, zipgereksiz bir liste oluşturmaktan kaçınmak için bir liste döndürür, izipbunun yerine kullanın (zip'e takma adı Python 3'e geçtiğinizde kod değişikliklerini azaltabilir).

from itertools import izip as zip

Bu hala (2.7):

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

Python 2, <= 2,6 için ideal

izipdan itertoolsolur zipPython 3'te izipPython 2 için zip daha iyidir 2.6 veya altı için ve ideali (gereksiz liste oluşturulmasını önler çünkü):

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

Tüm durumlar için sonuç:

Her durumda:

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

Açıklama:

Eğer yardım konusuna dictbakarsak, bunun çeşitli biçimler aldığını görürüz:


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

En uygun yaklaşım, gereksiz veri yapıları oluşturmaktan kaçınarak yinelenebilir bir yöntem kullanmaktır. Python 2'de zip, gereksiz bir liste oluşturur:

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

Python 3'te eşdeğer:

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

ve Python 3 zipsadece tekrarlanabilir bir nesne yaratır:

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

Gereksiz veri yapıları oluşturmaktan kaçınmak istediğimizden, genellikle Python 2'lerden kaçınmak isteriz zip(gereksiz bir liste oluşturduğundan).

Daha az performanslı alternatifler:

Bu, kurucu kurucuya iletilen bir üretici ifadesidir:

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

Veya eşdeğer olarak:

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

Ve bu, kurucu kurucuya aktarılan bir liste kavramasıdır:

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

İlk iki durumda, fermuarın üzerine ek bir operatif olmayan (dolayısıyla gereksiz) hesaplama katmanı yerleştirilir ve listenin anlaşılması durumunda, gereksiz bir ekstra liste oluşturulur. Hepsinin daha az performans göstermesini ve kesinlikle daha fazla olmasını beklemem.

Performans incelemesi:

Nix tarafından sağlanan 64 bit Python 3.8.2'de Ubuntu 16.04'te en hızlıdan en yavaşına doğru sıralandı:

>>> 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)) küçük anahtar ve değer kümeleriyle bile kazanır, ancak daha büyük kümeler için performans farklılıkları artar.

Bir yorumcu şunları söyledi:

minperformansı karşılaştırmanın kötü bir yolu gibi görünüyor. Elbette meanve / veya maxgerçek kullanım için çok daha yararlı göstergeler olacaktır.

Biz kullanmak minbu algoritmalar deterministik çünkü. Algoritmaların performansını mümkün olan en iyi koşullar altında bilmek istiyoruz.

İşletim sistemi herhangi bir nedenle askıda kalırsa, karşılaştırmaya çalıştığımız şeyle ilgisi yoktur, bu nedenle bu tür sonuçları analizimizden hariç tutmamız gerekir.

Kullandığımız takdirde mean, olayların bu tür büyük ölçüde sonuçlarını saptırma olur ve biz kullanılırsa maxbiz sadece en uç sonuç alırsınız - büyük olasılıkla böyle bir olay etkilenen biri.

Bir yorumcu ayrıca şunları söylüyor:

Python 3.6.8'de, ortalama değerleri kullanarak, bu küçük listeler için dikte anlama gerçekten daha hızlıdır, yaklaşık% 30 oranındadır. Daha büyük listeler için (10k rasgele sayılar), dictarama yaklaşık% 10 daha hızlıdır.

Sanırım dict(zip(...10k rasgele sayılarla kastediyoruz . Bu oldukça sıra dışı bir kullanım durumu gibi geliyor. Büyük veri kümelerinde en doğrudan çağrıların baskın olacağı mantıklıdır ve bu testi çalıştırmanın ne kadar süreceği ve sayılarınızı daha da arttırarak işletim sistemi askıda kalıyorsa şaşırmam. Ve eğer kullanırsanız meanya da maxsonuçlarınızı anlamsız olarak değerlendirirsem.

En iyi örneklerimizde daha gerçekçi bir boyut kullanalım:

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

Ve burada görüyoruz ki dict(zip(..., bu daha büyük veri kümeleri için yaklaşık% 20 daha hızlı çalışıyor.

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

1
2019 ortasından itibaren (python 3.7.3) farklı zamanlamalar buluyorum. %% timeit, 1.57 \ pm 0.019microsec değerini dict(zip(headList, textList))& 1.95 \ pm 0.030 microsec değerini döndürür {k: v for k, v in zip(headList, textList)}. Öncekini okunabilirlik ve hız için öneririm. Açıkçası bu timeit için min () vs mean () argümanına ulaşır.
Mark_Anderson

1
minperformansı karşılaştırmanın kötü bir yolu gibi görünüyor. Elbette meanve / veya maxgerçek kullanım için çok daha yararlı göstergeler olacaktır.
naught101

1
Python 3.6.8'de, ortalama değerleri kullanarak, bu küçük listeler için dikte anlama gerçekten daha hızlıdır, yaklaşık% 30 oranındadır. Daha büyük listeler için (10k rasgele sayılar), dictarama yaklaşık% 10 daha hızlıdır.
naught101

@ naught101 - Cevabımda yorumlarınıza hitap ettim.
Aaron Hall

3
10k sayıları, 2 uzun benzersiz öğe listesi oluşturmanın hızlı bir yoluydu. Liste oluşturma, zamanlama tahminlerinin dışında yapıldı. / / Sizce neden ortalama veya maksimum işe yaramaz? Bunu birçok kez yapıyorsanız, ortalama süreniz ~ n * ortalama ve üst sınır ~ n * maks. Minimum değeriniz daha düşük bir sınır sağlar, ancak çoğu insan ortalama veya en kötü durum performansına önem verir. Yüksek bir varyans varsa, minimum durumunuz çoğu durumda tamamen temsil edilmeyecektir. Minimum gerçek dünya senaryosunda nasıl daha anlamlı?
naught101

128

Bunu dene:

>>> 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'de, bellek tüketiminde kıyasla daha ekonomiktir zip.


18
Python2 için doğrudur, ancak Python 3'te zipbellek tüketiminde zaten ekonomiktir. docs.python.org/3/library/functions.html#zip Aslında, Python 3'ün Python 2 pythonhosted.org/six yerine değiştirmek için sixkullandığını görebilirsiniz . zipitertools.izip
Pedro Cattori

35
>>> keys = ('name', 'age', 'food')
>>> values = ('Monty', 42, 'spam')
>>> dict(zip(keys, values))
{'food': 'spam', 'age': 42, 'name': 'Monty'}

28

Python ≥ 2.7'de sözlük anlamlarını da kullanabilirsiniz:

>>> keys = ('name', 'age', 'food')
>>> values = ('Monty', 42, 'spam')
>>> {k: v for k, v in zip(keys, values)}
{'food': 'spam', 'age': 42, 'name': 'Monty'}

17

Daha doğal bir yol sözlük anlamayı kullanmaktır

keys = ('name', 'age', 'food')
values = ('Monty', 42, 'spam')    
dict = {keys[i]: values[i] for i in range(len(keys))}

bazen en hızlı ve bazen dictnesneye dönüştürmek en yavaş , neden öyle ?, teşekkürler dostum.
Haritsinh Gohil


10

Python 3.x ile diksiyon kavramaya gider

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

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

print(dic)

Diksiyon kavrayışları hakkında daha fazla bilgi için bir örnek var:

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

8

Basit koda ihtiyaç duyan ve aşina olmayanlar için zip:

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

Bu bir kod satırı ile yapılabilir:

d = {List1[n]: List2[n] for n in range(len(List1))}

6
List1daha uzunsa yüksek sesle başarısızList2
Jean-François Fabre

@ Jean-FrançoisFabre Gerçekten önemli mi? sözlük oluşturmak için farklı uzunlukta iki liste kullanmamızın nedeni nedir?
loved.by.Jesus

muhtemelen değil, ama bundan sonra for n in range(len(List1))bir anti-desen
Jean-François Fabre

3
  • 2018/04/18

En iyi çözüm hala:

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

Alıştırma yapın:

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

2

Aşağıdaki kodu kullanabilirsiniz:

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

Ancak listelerin uzunluğunun aynı olduğundan emin olun. Uzunluk aynı değilse, zip işlevi daha uzun olanı çevirir.


2

Grafikle ilgili bir sorunu çözmeye çalışırken bu şüphem vardı. Sahip olduğum sorun, boş bir bitişik liste tanımlamam gerekiyordu ve tüm düğümleri boş bir listeyle başlatmak istedim, o zaman yeterince hızlı olup olmadığını nasıl kontrol edeceğimi düşündüm, yani bir zip işlemi yapmaya değip değmeyeceğini düşündüm basit atama anahtar / değer çifti yerine. Çoğu zaman, zaman faktörü önemli bir buz kırıcıdır. Bu yüzden her iki yaklaşım için de timeit operasyonu yaptım.

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 için anladım,

Yineleme: 2.825081646999024 Kestirme: 3.535717916001886

Yineleme: 5.051560923002398 Kestirme: 6.255070794999483

Yineleme: 6.52859034499852 Kestirme: 8.221581164998497

Yineleme: 8.683652416999394 Kestirme: 12.599181543999293

Yineleme: 11.587241565001023 Kestirme: 15.27298851100204

Yineleme: 14.816342867001367 Kestirme: 17.162912737003353

Yineleme: 16.645022411001264 Kestirme: 19.976680120998935

Belirli bir noktadan sonra n_th adımda yineleme yaklaşımının n-1_th adımda steno yaklaşım ile harcanan süreyi aştığını açıkça görebilirsiniz.


1

Ayrıca, sözlüğünüze liste değeri ekleme örneği

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

daima "Anahtarınızın" (liste1) daima ilk parametrede olduğundan emin olun.

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

0

Numaralandırma ile sözlük anlama olarak çözüm:

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

Numaralı döngü için çözüm:

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

0

Ayrıca, iki listenin birleşimi olan bir liste ile de deneyebilirsiniz;)

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

-1

zip fonksiyonu olmayan yöntem

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

Merhaba xiyurui, Girdi (l1 ve l2) bir liste olmalıdır. L1 ve l2'yi küme olarak atarsanız, ekleme sırasını koruyamayabilir. benim için çıktıyı {1: 'a', 2: 'c', 3: 'd', 4: 'b', 5: 'e'} olarak
aldım
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.