[python] 두 목록을 사전으로 변환

당신이 가지고 있다고 상상해보십시오 :

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}

Voila 🙂 pairwise dict생성자와 zip함수는 매우 유용합니다 : https://docs.python.org/3/library/functions.html#func-dict


답변

당신이 가지고 있다고 상상해보십시오 :

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

다음 사전을 생성하는 가장 간단한 방법은 무엇입니까?

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

성능이 가장 뛰어난 dict생성자zip

new_dict = dict(zip(keys, values))

Python 3에서 zip은 이제 lazy iterator를 반환하며 이것이 가장 성능이 좋은 방법입니다.

dict(zip(keys, values))dictzip에 대한 일회성 전역 조회가 각각 필요 하지만 불필요한 중간 데이터 구조를 형성하지 않거나 함수 애플리케이션에서 로컬 조회를 처리해야합니다.

준우승, 독해 :

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

파이썬 2, <= 2.6에 이상적

izipfrom itertoolszipPython 3 izip이 됩니다 . 불필요한 목록 생성을 피하기 때문에 Python 2의 zip보다 낫고 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')]

파이썬 3은 zip단순히 반복 가능한 객체를 만듭니다.

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

불필요한 데이터 구조를 만드는 것을 피하고 싶기 때문에, 파이썬 2 zip는 불필요한리스트를 생성하기 때문에 피하는 것이 좋습니다.

성능이 떨어지는 대안 :

이것은 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 iterable 위에 배치되고 목록 이해의 경우 추가 목록이 불필요하게 작성됩니다. 나는 그들 모두 성능이 떨어질 것이라고 기대할 것입니다.

성능 검토 :

Ubuntu 16.04에서 Nix가 제공하는 64 비트 Python 3.8.2에서 가장 빠른 것부터 가장 느린 것까지 순서 :

>>> 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성능을 비교하는 나쁜 방법 인 것 같습니다. 확실히 mean및 / 또는 max실제 사용에 대한 훨씬 더 유용한 지표가 될 것입니다.

min이러한 알고리즘은 결정론 적이므로 사용 합니다. 최상의 조건에서 알고리즘의 성능을 알고 싶습니다.

어떤 이유로 든 운영 체제가 중단되면 비교하려는 것과 아무런 관련이 없으므로 이러한 유형의 결과를 분석에서 제외해야합니다.

를 사용 mean하면 이러한 종류의 이벤트가 결과를 크게 왜곡하고 사용 max하면 가장 극단적 인 결과 만 얻을 수 있습니다.

논평자는 또한 말합니다 :

python 3.6.8에서 평균 값을 사용하면 작은 목록의 경우 dict 이해력이 여전히 약 30 % 빠릅니다. 더 큰 목록 (10k 난수)의 경우 dict통화가 약 10 % 빠릅니다.

dict(zip(...10k의 난수를 의미한다고 가정 합니다. 그것은 꽤 특이한 사용 사례처럼 들립니다. 가장 직접적인 호출은 큰 데이터 세트에서 지배적이며, OS 테스트가 해당 테스트를 실행하는 데 걸리는 시간이 오래 걸리고 숫자가 더 치우친 경우 놀라지 않을 것입니다. 그리고 당신이 사용하는 경우 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


답변

이 시도:

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


답변

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


답변

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


답변

보다 자연스러운 방법은 사전 이해력을 사용하는 것입니다

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


답변

사전을 작성하기 전에 키 또는 값을 변환해야하는 경우 생성기 표현식 을 사용할 수 있습니다. 예:

>>> adict = dict((str(k), v) for k, v in zip(['a', 1, 'b'], [2, 'c', 3])) 

Pythonista : Idiomatic Python과 같은 코드를 살펴보십시오 .