Odpowiedzi:
Lubię to:
>>> keys = ['a', 'b', 'c']
>>> values = [1, 2, 3]
>>> dictionary = dict(zip(keys, values))
>>> print(dictionary)
{'a': 1, 'b': 2, 'c': 3}
Voila :-) dict
Konstruktor i zip
funkcja parujące są niezwykle przydatne: https://docs.python.org/3/library/functions.html#func-dict
{thing}
jest cukrem syntaktycznym do skonstruowania set()
zawierającego jeden element. {*iterable}
jest cukrem syntaktycznym do skonstruowania set
zawierającego kilka elementów. {k:v}
lub {**mapping}
będzie skonstruować dict
, ale to składniowo zupełnie odrębne.
{}
do słowników. W rzeczywistości, jeśli spróbujemy, type({})
wynik będzie dict
. Ale rzeczywiście, jeśli spróbujemy, type({thing})
wynik będzie set
.
{k:v for k, v in zip(keys, values)}
. Okazuje się, że możemy. +1.
Wyobraź sobie, że masz:
keys = ('name', 'age', 'food') values = ('Monty', 42, 'spam')
Jaki jest najprostszy sposób na utworzenie następującego słownika?
dict = {'name' : 'Monty', 'age' : 42, 'food' : 'spam'}
dict
konstruktorzip
new_dict = dict(zip(keys, values))
W Pythonie 3 zip zwraca teraz leniwy iterator i jest to obecnie najbardziej wydajne podejście.
dict(zip(keys, values))
wymaga każdorazowego jednorazowego globalnego wyszukiwania dict
i zip
, ale nie tworzy niepotrzebnych pośrednich struktur danych ani nie musi zajmować się lokalnymi przeglądami w aplikacji funkcji.
Drugim miejscem do korzystania z konstruktora dict jest użycie natywnej składni rozumienia dict (nie rozumienia listy , jak inni błędnie to powiedzieli):
new_dict = {k: v for k, v in zip(keys, values)}
Wybierz tę opcję, gdy chcesz mapować lub filtrować na podstawie kluczy lub wartości.
W Pythonie 2 zip
zwraca listę, aby uniknąć tworzenia niepotrzebnej listy, użyj izip
zamiast tego (aliasy do zip mogą zmniejszyć zmiany kodu po przejściu do Pythona 3).
from itertools import izip as zip
Tak więc nadal (2.7):
new_dict = {k: v for k, v in zip(keys, values)}
izip
from itertools
staje się zip
w Pythonie 3. izip
jest lepszy niż zip dla Pythona 2 (ponieważ pozwala uniknąć niepotrzebnego tworzenia listy) i idealny dla wersji 2.6 lub niższej:
from itertools import izip
new_dict = dict(izip(keys, values))
We wszystkich przypadkach:
>>> new_dict
{'age': 42, 'name': 'Monty', 'food': 'spam'}
Jeśli spojrzymy na pomoc dict
, widzimy, że wymaga ona różnych form argumentów:
>>> 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)
Optymalnym podejściem jest stosowanie iterowalności, przy jednoczesnym unikaniu tworzenia niepotrzebnych struktur danych. W Pythonie 2 zip tworzy niepotrzebną listę:
>>> zip(keys, values)
[('name', 'Monty'), ('age', 42), ('food', 'spam')]
W Pythonie 3 odpowiednikiem byłoby:
>>> list(zip(keys, values))
[('name', 'Monty'), ('age', 42), ('food', 'spam')]
a Python 3 zip
tworzy jedynie iterowalny obiekt:
>>> zip(keys, values)
<zip object at 0x7f0e2ad029c8>
Ponieważ chcemy uniknąć tworzenia niepotrzebnych struktur danych, zwykle chcemy uniknąć Pythona 2 zip
(ponieważ tworzy niepotrzebną listę).
To wyrażenie generatora jest przekazywane do konstruktora dict:
generator_expression = ((k, v) for k, v in zip(keys, values))
dict(generator_expression)
lub równoważnie:
dict((k, v) for k, v in zip(keys, values))
Oto koncept listy przekazywany konstruktorowi dykt:
dict([(k, v) for k, v in zip(keys, values)])
W pierwszych dwóch przypadkach dodatkowa warstwa nieoperacyjnego (a więc niepotrzebnego) obliczenia jest umieszczana nad iterowalnym zamkiem błyskawicznym, aw przypadku zrozumienia listy niepotrzebnie tworzona jest dodatkowa lista. Spodziewałbym się, że wszystkie będą mniej wydajne, a na pewno nie bardziej.
W 64-bitowym Pythonie 3.8.2 dostarczonym przez Nix na Ubuntu 16.04, uporządkowanym od najszybszego do najwolniejszego:
>>> 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))
wygrywa nawet przy małych zestawach kluczy i wartości, ale w przypadku większych zestawów różnice w wydajności będą większe.
Komentator powiedział:
min
wydaje się zły sposób na porównanie wydajności. Z pewnościąmean
i / lubmax
byłyby o wiele bardziej przydatne wskaźniki do rzeczywistego wykorzystania.
Używamy, min
ponieważ te algorytmy są deterministyczne. Chcemy poznać wydajność algorytmów w najlepszych możliwych warunkach.
Jeśli system operacyjny zawiesza się z jakiegokolwiek powodu, nie ma to nic wspólnego z tym, co próbujemy porównać, dlatego musimy wykluczyć tego rodzaju wyniki z naszej analizy.
Gdybyśmy zastosowali mean
, tego rodzaju zdarzenia znacznie zniekształcałyby nasze wyniki, a gdybyśmy zastosowali, max
otrzymalibyśmy tylko najbardziej ekstremalny wynik - ten, na który najprawdopodobniej wpłynie takie zdarzenie.
Komentator mówi również:
W Pythonie 3.6.8, przy użyciu wartości średnich, zrozumienie dykta jest rzeczywiście jeszcze szybsze, o około 30% dla tych małych list. W przypadku większych list (10 000 losowych numerów)
dict
połączenie jest około 10% szybsze.
Zakładam, że mamy na myśli dict(zip(...
10k liczb losowych. To brzmi jak dość nietypowy przypadek użycia. To ma sens, że najbardziej bezpośrednie połączenia dominują w dużych zestawach danych i nie zdziwiłbym się, gdyby zawieszenia systemu dominowały, biorąc pod uwagę, ile czasu zajęłoby uruchomienie tego testu, dodatkowo wypaczając liczby. A jeśli użyjesz mean
lub max
uznałbym twoje wyniki za bezsensowne.
Zastosujmy bardziej realistyczny rozmiar w naszych najlepszych przykładach:
import numpy
import timeit
l1 = list(numpy.random.random(100))
l2 = list(numpy.random.random(100))
Widzimy tutaj, że dict(zip(...
rzeczywiście działa szybciej dla większych zestawów danych o około 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))
i 1,95 \ pm 0,030 mikrosekundy dla {k: v for k, v in zip(headList, textList)}
. Sugerowałbym ten pierwszy ze względu na czytelność i szybkość. Oczywiście jest to argument argumentu min () vs mean () dla timeit.
min
wydaje się zły sposób na porównanie wydajności. Z pewnością mean
i / lub max
byłyby o wiele bardziej przydatne wskaźniki do rzeczywistego wykorzystania.
dict
połączenie jest około 10% szybsze.
Spróbuj tego:
>>> import itertools
>>> keys = ('name', 'age', 'food')
>>> values = ('Monty', 42, 'spam')
>>> adict = dict(itertools.izip(keys,values))
>>> adict
{'food': 'spam', 'age': 42, 'name': 'Monty'}
W Pythonie 2 zużycie pamięci jest również bardziej ekonomiczne w porównaniu do zip
.
zip
jest już oszczędny w zużyciu pamięci. docs.python.org/3/library/functions.html#zip W rzeczywistości widać, że six
używa zip
Python 3 do zastępowania itertools.izip
w Python 2 pythonhosted.org/six .
W języku Python ≥ 2.7 możesz także używać wyrażeń słownikowych:
>>> keys = ('name', 'age', 'food')
>>> values = ('Monty', 42, 'spam')
>>> {k: v for k, v in zip(keys, values)}
{'food': 'spam', 'age': 42, 'name': 'Monty'}
Bardziej naturalnym sposobem jest użycie słownika
keys = ('name', 'age', 'food')
values = ('Monty', 42, 'spam')
dict = {keys[i]: values[i] for i in range(len(keys))}
dict
obiekt, dlaczego tak jest ?, dzięki, stary.
Jeśli potrzebujesz przekształcić klucze lub wartości przed utworzeniem słownika, możesz użyć wyrażenia generatora . Przykład:
>>> adict = dict((str(k), v) for k, v in zip(['a', 1, 'b'], [2, 'c', 3]))
Spójrz Kod jak Pythonista: Idiomatic Python .
w Pythonie 3.x chodzi o rozumienie nagrań
keys = ('name', 'age', 'food')
values = ('Monty', 42, 'spam')
dic = {k:v for k,v in zip(keys, values)}
print(dic)
Więcej na temat rozumienia nagrań tutaj , przykład:
>>> print {i : chr(65+i) for i in range(4)}
{0 : 'A', 1 : 'B', 2 : 'C', 3 : 'D'}
Dla tych, którzy potrzebują prostego kodu i nie są zaznajomieni z zip
:
List1 = ['This', 'is', 'a', 'list']
List2 = ['Put', 'this', 'into', 'dictionary']
Można to zrobić za pomocą jednego wiersza kodu:
d = {List1[n]: List2[n] for n in range(len(List1))}
List1
jest dłuższy niżList2
for n in range(len(List1))
jest anty-wzór
Najlepszym rozwiązaniem jest nadal:
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'}
Przepisz to:
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')
możesz użyć tego kodu poniżej:
dict(zip(['name', 'age', 'food'], ['Monty', 42, 'spam']))
Ale upewnij się, że długość list będzie taka sama. Jeśli długość nie jest taka sama. Następnie funkcja zip obróć dłuższą.
Miałem wątpliwości, gdy próbowałem rozwiązać problem związany z grafem. Problemem było to, że musiałem zdefiniować pustą listę przylegania i chciałem zainicjować wszystkie węzły z pustą listą, wtedy pomyślałem o tym, czy sprawdzę, czy jest wystarczająco szybki, to znaczy, czy warto wykonać operację zip zamiast prostej pary klucz-wartość przypisania. W większości przypadków czynnik czasu jest ważnym czynnikiem łamającym lód. Więc wykonałem operację timeit dla obu podejść.
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)}')
Za n_nodes = 10 000 000 dostaję,
Iteracja: 2,825081646999024 Stenografia: 3,535717916001886
Iteracja: 5.051560923002398 Stenografia: 6,255070794999483
Iteracja: 6,52859034499852 Stenografia: 8,221581164998497
Iteracja: 8.683652416999394 Stenografia: 12.599181543999293
Iteracja: 11.587241565001023 Stenografia: 15,27298851100204
Iteracja: 14,816342867001367 Stenografia: 17.162912737003353
Iteracja: 16,645022411001264 Skrót: 19,976680120998935
Po pewnym punkcie widać wyraźnie, że podejście iteracyjne na n-tym kroku wyprzedza czas potrzebny na podejście skrótowe na n-1 kroku.
Oto także przykład dodania wartości listy do słownika
list1 = ["Name", "Surname", "Age"]
list2 = [["Cyd", "JEDD", "JESS"], ["DEY", "AUDIJE", "PONGARON"], [21, 32, 47]]
dic = dict(zip(list1, list2))
print(dic)
zawsze upewnij się, że Twój „klucz” (lista1) jest zawsze w pierwszym parametrze.
{'Name': ['Cyd', 'JEDD', 'JESS'], 'Surname': ['DEY', 'AUDIJE', 'PONGARON'], 'Age': [21, 32, 47]}
Możesz także spróbować z jedną listą, która jest kombinacją dwóch list;)
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])))
metoda bez funkcji 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'}
dictionary = {zip(keys, values)}
to nie zadziała. Musisz jawnie zadeklarować jakodict(...)