programing

Python에서 두 개의 사전을 하나의 식에 병합하려면 어떻게 해야 합니까?

batch 2023. 4. 16. 14:46
반응형

Python에서 두 개의 사전을 하나의 식에 병합하려면 어떻게 해야 합니까?

나는 두 사전을 새 사전으로 합치고 싶다.

x = {'a': 1, 'b': 2}
y = {'b': 3, 'c': 4}
z = merge(x, y)

>>> z
{'a': 1, 'b': 3, 'c': 4}

를 누를 k는 양쪽.y[k]보관해야 합니다.

두 개의 Python 사전을 하나의 식에 병합하려면 어떻게 해야 합니까?

의 경우x ★★★★★★★★★★★★★★★★★」y, 얄팍한 사전.z을 취득하다y, 에서 온 것을 교환합니다.x.

  • Python 3.9.0 이상(2020년 10월 17일 출시, 여기서 설명):

    z = x | y
    
  • Python 3.5 이상에서는:

    z = {**x, **y}
    
  • Python 2에서는 (또는 3.4 이하) 함수를 작성합니다.

    def merge_two_dicts(x, y):
        z = x.copy()   # start with keys and values of x
        z.update(y)    # modifies z with keys and values of y
        return z
    

    그리고 지금:

    z = merge_two_dicts(x, y)
    

설명.

두 개의 사전이 있고 원본 사전을 변경하지 않고 새 사전으로 병합하려고 합니다.

x = {'a': 1, 'b': 2}
y = {'b': 3, 'c': 4}

는 새 것이다z두 번째 사전의 값이 첫 번째 사전의 값을 덮어씁니다.

>>> z
{'a': 1, 'b': 3, 'c': 4}

PEP 448에서 제안되고 Python 3.5에서 사용할 수 있는 새로운 구문은 다음과 같습니다.

z = {**x, **y}

그리고 그것은 정말로 하나의 표현이다.

리터럴 표기법에서도 머지할 수 있습니다.

z = {**x, 'foo': 1, 'bar': 2, **y}

그리고 지금:

>>> z
{'a': 1, 'b': 3, 'foo': 1, 'bar': 2, 'c': 4}

3.5, PEP 478의 릴리즈 스케줄에 실장되어 있으며, 현재 Python 3.5의 What's New 문서에도 실장되어 있습니다.

그러나 많은 조직이 여전히 Python 2에 있기 때문에 하위 호환성을 가진 방법으로 이 작업을 수행할 수 있습니다.Python 2 및 Python 3.0-3.4에서 사용할 수 있는 고전적인 Pythonic 방법은 이를 2단계 프로세스로 수행하는 것입니다.

z = x.copy()
z.update(y) # which returns None since it mutates z

접근법 모두 " " " 입니다.y 그 will will will 、 will will 、 will will 、 will will will will will will will will will will will will will will will will will will will will will 。x의 값,즉 " ", "b 가리키다3우리의 최종 결과입니다.

Python 3.5에서는 아직 사용할 수 없지만 하나의 식을 원합니다.

Python 3.5를 아직 사용하지 않았거나 하위 호환 코드를 작성해야 하며, 이를 단일 표현으로 작성하려면 함수에 넣는 것이 가장 성능적이지만 올바른 접근법입니다.

def merge_two_dicts(x, y):
    """Given two dictionaries, merge them into a new dict as a shallow copy."""
    z = x.copy()
    z.update(y)
    return z

그리고 한 가지 표현이 있습니다.

z = merge_two_dicts(x, y)

0부터 매우 큰 숫자까지 임의의 수의 사전을 병합하는 함수를 만들 수도 있습니다.

def merge_dicts(*dict_args):
    """
    Given any number of dictionaries, shallow copy and merge into a new dict,
    precedence goes to key-value pairs in latter dictionaries.
    """
    result = {}
    for dictionary in dict_args:
        result.update(dictionary)
    return result

2및 예를 들어,은 Python 2 및 3입니다.a로로 합니다.g:

z = merge_dicts(a, b, c, d, e, f, g) 

이 「」로 표시됩니다.g보다 a로로 합니다.f기타 등등.

기타 답변에 대한 비판

이전에 승인된 답변에 표시된 내용을 사용하지 마십시오.

z = dict(x.items() + y.items())

Python 2에서는 각 dict에 대해 메모리에 두 개의 목록을 만들고, 메모리 내에 처음 두 개의 목록을 합친 길이와 같은 세 번째 목록을 만든 다음, 세 개의 목록을 모두 폐기하여 dict를 만듭니다.Python 3 에서는, 2개를 추가하고 있기 때문에, 이것은 실패합니다.dict_items2개의합친 입니다.

>>> c = dict(a.items() + b.items())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'dict_items' and 'dict_items'

리스트로 . 예를 리스트로 해야 합니다.z = dict(list(x.items()) + list(y.items()))이치노

마찬가지로, 의 결합을 취한다.items()3 (Python 3 서서 ()viewitems()Python 2.7에서는 값이 캐시할 수 없는 개체(예: 목록)인 경우에도 실패합니다.이 해시 가능하더라도 집합은 의미적으로 순서가 매겨지지 않으므로 우선순위에 대한 동작은 정의되지 않습니다. 그러니 그러지 마세요.

>>> c = dict(a.items() | b.items())

다음 예시는 값을 캐시할 수 없는 경우의 동작을 보여 줍니다.

>>> x = {'a': []}
>>> y = {'b': []}
>>> dict(x.items() | y.items())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

를 들면, 이 경우 입니다.y, precedence의 값, from의 값,x집합의 로 인해 됩니다.

>>> x = {'a': 2}
>>> y = {'a': 1}
>>> dict(x.items() | y.items())
{'a': 2}

사용해서는 안 되는 또 다른 해킹:

z = dict(x, **y)

은 「」를 합니다.dict컨스트럭터이며 매우 빠르고 메모리 효율적입니다(당사의 2단계 프로세스보다 약간 더 높음). 하지만 여기서 무슨 일이 일어나고 있는지 정확히 알지 못하는 한(즉, 두 번째 dict는 키워드 인수로 전달됨), 읽기 어렵고 의도된 용법이 아니기 때문에 피토닉이 아닙니다.

다음은 django에서 수정되는 사용 예시를 보여드리겠습니다.

은 해시 한 키 " " " " )를 사용하기 위한 입니다.frozensets 또는 tuples). 단, 키가 문자열이 아닌 경우 메서드는 Python 3에서 실패합니다.

>>> c = dict(a, **b)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: keyword arguments must be strings

메일링 리스트에서 이 언어를 만든 Guido van Rossum은 다음과 같이 썼다.

dict({}, **{1:3})가 불법이라고 선언하는 것은 결국 ** 메커니즘의 오용이기 때문에 괜찮습니다.

그리고.

dict(x, **y)는 "call x.update(y) and return x"의 "cool hack"으로 돌고 있는 것 같습니다.개인적으로, 나는 그것이 쿨하기보다 더 비열하다고 생각한다.

(언어 작성자의 이해와 더불어) 의 의도된 사용법은 다음과 같습니다.dict(**y)는 가독성을 목적으로 사전을 작성하기 위한 것입니다.예를 들어 다음과 같습니다.

dict(a=1, b=10, c=11)

대신

{'a': 1, 'b': 10, 'c': 11}

코멘트에 대한 응답

귀도의 말에도 불구하고dict(x, **y)는, 2와 3의 양쪽 사양에 하고 있습니다.이 사양은 Python 2 와 3 의 양쪽 에서 동작합니다.이것이 문자열 키에서만 작동한다는 사실은 키워드 파라미터의 동작 방식에 직접적인 영향을 미치며 dict의 단점은 아닙니다.여기서 ** 연산자를 사용하는 것도 메커니즘을 남용하는 것은 아닙니다.사실 **는 사전을 키워드로 전달하도록 설계되어 있습니다.

다시 말하지만 키가 문자열이 아닌 경우 3은 작동하지 않습니다.암묵적인 콜 계약에서는 네임스페이스가 일반 사전을 사용하는 반면 사용자는 문자열인 키워드 인수만 전달해야 합니다.른른른른dictPython 2 서 python python 에 python python python python python python python 。

>>> foo(**{('a', 'b'): None})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() keywords must be strings
>>> dict(**{('a', 'b'): None})
{('a', 'b'): None}

Python의 다른 구현(PyPy, Jython, IronPython)을 고려할 때 이러한 불일치는 좋지 않았습니다.따라서 Python 3에서는 수정되었습니다.이러한 사용은 큰 변화가 될 수 있기 때문입니다.

한 버전의 언어에서만 작동하는 코드 또는 임의의 제약이 있을 때만 작동하는 코드를 의도적으로 작성하는 것은 악의적인 무능이라는 것을 알려드립니다.

기타 코멘트:

dict(x.items() + y.items()) Python2에서 쉬운 입니다.가독성이 중요합니다.

★★★★★★★★★★★★★★」merge_two_dicts(x, y)점점 권장되지 않기 .또한 Python 2는 점점 더 권장되지 않기 때문에 포워드 호환성이 없습니다.

{**x, **y}은 단순히 않는 버렸고 .중첩된 키의 내용은 병합된 것이 아니라 단순히 덮어쓰기됩니다.[...] 재귀적으로 병합되지 않는 이러한 답변에 속아 넘어갔는데 아무도 언급하지 않은 것에 놀랐습니다."하면, 은 " 쪽 딕트를 다른 쪽 딕트로 하는 병합하는 것이 머징"이라는 단어를 해석하면, 이러한 답변은 "한 쪽 딕트를 다른 쪽 딕트로 업데이트"하는 것이지, 병합하는 것이 아닙니다.

네, 두 사전얄팍한 병합을 요구하고, 두 번째 사전의 값을 두 번째 사전의 값으로 덮어쓰는 문제를 한 번 더 언급해야 합니다.

두 개의 사전이 있다고 가정할 때 한 개의 사전이 하나의 함수로 반복적으로 병합될 수 있지만, 어느 소스에서도 사전을 수정하지 않도록 주의해야 합니다.그리고 이를 피하기 위한 가장 확실한 방법은 값을 할당할 때 복사본을 만드는 것입니다.키는 해시 가능해야 하므로 일반적으로 불변이므로 복사하는 것은 의미가 없습니다.

from copy import deepcopy

def dict_of_dicts_merge(x, y):
    z = {}
    overlapping_keys = x.keys() & y.keys()
    for key in overlapping_keys:
        z[key] = dict_of_dicts_merge(x[key], y[key])
    for key in x.keys() - overlapping_keys:
        z[key] = deepcopy(x[key])
    for key in y.keys() - overlapping_keys:
        z[key] = deepcopy(y[key])
    return z

사용방법:

>>> x = {'a':{1:{}}, 'b': {2:{}}}
>>> y = {'b':{10:{}}, 'c': {11:{}}}
>>> dict_of_dicts_merge(x, y)
{'b': {2: {}, 10: {}}, 'a': {1: {}}, 'c': {11: {}}}

다른 가치 유형에 대한 우발적인 대처는 이 질문의 범위를 훨씬 벗어나 있기 때문에, 「사전 병합」관한 표준적인 질문에 대한 나의 답변을 가르쳐 주겠다.

성능은 떨어지지만 적절한 애드혹

이러한 접근 방식은 성능은 떨어지지만 올바른 동작을 제공합니다.퍼포먼스가 훨씬 떨어집니다.copy ★★★★★★★★★★★★★★★★★」update또는 상위 추상화 수준에서 각 키와 값의 쌍을 반복하지만 우선순위는 존중하기 때문에 새로운 패키징이 해제됩니다(사전에는 우선순위가 있습니다).

딕트 이해 내에서 사전을 수동으로 체인할 수도 있습니다.

{k: v for d in dicts for k, v in d.items()} # iteritems in Python 2.7

또는 Python 2.6(제너레이터 표현식이 도입되었을 때 2.4부터):

dict((k, v) for d in dicts for k, v in d.items()) # iteritems in Python 2

itertools.chain에 대해 으로 합니다.즉, 「」, 「 」, 「 」, 「 」, 「 」의 순서로 합니다.

from itertools import chain
z = dict(chain(x.items(), y.items())) # iteritems in Python 2

퍼포먼스 분석

올바르게 동작하는 것으로 알려진 사용법의 퍼포먼스 분석만 실시합니다.(스스로 복사하여 붙여넣을 수 있습니다.)

from timeit import repeat
from itertools import chain

x = dict.fromkeys('abcdefg')
y = dict.fromkeys('efghijk')

def merge_two_dicts(x, y):
    z = x.copy()
    z.update(y)
    return z

min(repeat(lambda: {**x, **y}))
min(repeat(lambda: merge_two_dicts(x, y)))
min(repeat(lambda: {k: v for d in (x, y) for k, v in d.items()}))
min(repeat(lambda: dict(chain(x.items(), y.items()))))
min(repeat(lambda: dict(item for d in (x, y) for item in d.items())))

Python 3.8.1에서는 NixOS:

>>> min(repeat(lambda: {**x, **y}))
1.0804965235292912
>>> min(repeat(lambda: merge_two_dicts(x, y)))
1.636518670246005
>>> min(repeat(lambda: {k: v for d in (x, y) for k, v in d.items()}))
3.1779992282390594
>>> min(repeat(lambda: dict(chain(x.items(), y.items()))))
2.740647904574871
>>> min(repeat(lambda: dict(item for d in (x, y) for item in d.items())))
4.266070580109954
$ uname -a
Linux nixos 4.19.113 #1-NixOS SMP Wed Mar 25 07:06:15 UTC 2020 x86_64 GNU/Linux

사전 리소스

고객의 경우 다음 작업을 수행할 수 있습니다.

z = dict(list(x.items()) + list(y.items()))

원하는 대로 것, 신, 신, 지, 지, 지, 지, 지, 지, 지, 지, 지, 지, this, this, this, this, this, this, this에 넣을 수 있습니다zby 값 dict dict : :

>>> x = {'a': 1, 'b': 2}
>>> y = {'b': 10, 'c': 11}
>>> z = dict(list(x.items()) + list(y.items()))
>>> z
{'a': 1, 'c': 11, 'b': 10}

2를 하면 Python 2를 .list()z: 출 z z.z를 하려면:

>>> z = dict(x.items() + y.items())
>>> z
{'a': 1, 'c': 11, 'b': 10}

Python 버전 3.9.0a4 이상을 사용하는 경우 다음을 직접 사용할 수 있습니다.

>>> x = {'a': 1, 'b': 2}
>>> y = {'b': 10, 'c': 11}
>>> z = x | y
>>> z
{'a': 1, 'c': 11, 'b': 10}

다른 방법:

z = x.copy()
z.update(y)

또 다른 간결한 옵션:

z = dict(x, **y)

주의: 이것은 일반적인 답변이 되었습니다만, 중요한 것은 다음과 같습니다.y는 문자열 이외의 키를 가지고 있습니다.이것은 CPython 구현의 상세 내용을 악용한 것으로, Python 3, Python, IronPython 또는 Jython에서는 동작하지 않습니다.그리고 Guido는 팬이 아닙니다.따라서 이 기술은 정방향 호환 또는 교차 구현 휴대용 코드에는 권장할 수 없습니다. 이는 완전히 피해야 한다는 것을 의미합니다.

이것은 아마 인기 있는 대답은 아닐 것입니다만, 당신은 이것을 하고 싶지 않을 것입니다.병합된 복사본을 원하는 경우, 복사(또는 원하는 내용에 따라 딥카피)를 사용한 후 업데이트합니다..items() + .items()를 사용한 단일 줄 작성보다 두 줄의 코드가 훨씬 읽기 쉽고 더 피토닉합니다.명시적인 것이 암묵적인 것보다 낫다.

또한 .items()(Python 3.0 이전)를 사용하면 dict의 항목을 포함하는 새 목록이 생성됩니다.사전이 크면 상당한 오버헤드가 발생합니다(마지된 dict가 생성되는 즉시 폐기되는 두 개의 큰 목록).update()는 두 번째 dict 항목별로 실행할 수 있기 때문에 보다 효율적으로 동작할 수 있습니다.

시간적 측면:

>>> timeit.Timer("dict(x, **y)", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
15.52571702003479
>>> timeit.Timer("temp = x.copy()\ntemp.update(y)", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
15.694622993469238
>>> timeit.Timer("dict(x.items() + y.items())", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
41.484580039978027

IMO는 첫 번째와 두 번째 사이의 작은 속도 저하는 가독성을 위해 가치가 있습니다.또한 사전 작성을 위한 키워드 인수는 Python 2.3에서만 추가되었지만 copy() 및 update()는 이전 버전에서 작동합니다.

후속 답변에서 다음 두 가지 대안의 상대적 성능에 대해 질문했습니다.

z1 = dict(x.items() + y.items())
z2 = dict(x, **y)

2. 매우 ), 인 (Python 2.5.2를 실행하고 있는)x86_64,z2더 짧고 단순할 뿐만 아니라 훨씬 더 빠릅니다.은 직접 하실 수 .timeit파이썬

예 1: 동일한 사전이 20개의 정수를 서로 매핑합니다.

% python -m timeit -s 'x=y=dict((i,i) for i in range(20))' 'z1=dict(x.items() + y.items())'
100000 loops, best of 3: 5.67 usec per loop
% python -m timeit -s 'x=y=dict((i,i) for i in range(20))' 'z2=dict(x, **y)' 
100000 loops, best of 3: 1.53 usec per loop

z23.상당히 것 , 마다 차이가 있습니다.z2항상 앞서는 것 같아요.(같은 테스트에서 일관성이 없는 결과가 나오면 합격해 보십시오.-r3을 사용하다

예 2: 252개의 짧은 문자열을 정수에 매핑하고 그 반대도 마찬가지입니다.

% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z1=dict(x.items() + y.items())'
1000 loops, best of 3: 260 usec per loop
% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z2=dict(x, **y)'               
10000 loops, best of 3: 26.9 usec per loop

z2 내 생각에 그건 꽤 큰 승리야!

, 는 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★?z1리스트의 에 의한 것일 수 있습니다, 이 이 더잘 하는 .그 결과, 이 변형이 더 잘 기능하지 않을까 하는 의문이 들었습니다.

from itertools import chain
z3 = dict(chain(x.iteritems(), y.iteritems()))

몇 가지 간단한 테스트, 예를 들어, 예:

% python -m timeit -s 'from itertools import chain; from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z3=dict(chain(x.iteritems(), y.iteritems()))'
10000 loops, best of 3: 66 usec per loop

라고 z3 다소 z1 못합니다.z2더 칠 도 전혀 추가 타이핑할 가치가 전혀 없습니다.

이 에는 아직 은, 2개의과의 「즉, 2개의 리스트를 사용하는 입니다.update x나 y를 수정하지 않는 x를 그대로 하지 않고, x.

z0 = dict(x)
z0.update(y)

일반적인 결과:

% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z0=dict(x); z0.update(y)'
10000 loops, best of 3: 26.9 usec per loop

말하면, 「 」입니다.z0 ★★★★★★★★★★★★★★★★★」z2기본적으로 동일한 성능을 가진 것 같습니다.게게 우연 ?일 치? ?? ??? ★★★★★★★★★…

사실 순수 Python 코드가 이것보다 더 잘 되는 것은 불가능하다고까지 말하고 싶습니다.만약 당신이 C 확장 모듈에서 훨씬 더 잘 할 수 있다면, Python 사람들은 당신의 코드(또는 당신의 접근 방식의 변형)를 Python 코어에 통합하는 것에 관심이 있을 것이라고 생각합니다.은 Python을 합니다.dict운영 최적화는 매우 중요합니다.

이것을 다음과 같이 쓸 수도 있다.

z0 = x.copy()
z0.update(y)

Tony는 그렇지만 (놀랍지도 않게) 표기법의 차이는 성능에 측정 가능한 영향을 미치지 않는 것으로 판명되었습니다.당신이 보기 좋은 것을 사용하세요.물론, 그가 두 개의 문장으로 된 버전이 훨씬 더 이해하기 쉽다고 지적한 것은 전적으로 옳다.

Python 3.0 이상에서는 여러 개의 딕트 또는 다른 매핑을 함께 그룹화하여 단일 업데이트 가능한 보기를 만들 수 있습니다.

>>> from collections import ChainMap
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = dict(ChainMap({}, y, x))
>>> for k, v in z.items():
        print(k, '-->', v)
    
a --> 1
b --> 10
c --> 11

Python 3.5 이상용 업데이트:PEP 448 확장 사전 패킹 및 언팩을 사용할 수 있습니다.이것은 빠르고 간단합니다.

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> {**x, **y}
{'a': 1, 'b': 10, 'c': 11}

Python 3.9 이후 업데이트:PEP 584 유니언 연산자를 사용할 수 있습니다.

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> x | y
{'a': 1, 'b': 10, 'c': 11}

같은 것을 원했지만, 중복 키의 값이 어떻게 Marge 되는지를 지정할 수 있기 때문에, 이것을 해킹했습니다(그러나, 테스트의 강도를 높이지 않았습니다).분명히 이것은 단일 표현은 아니지만 단일 함수 호출입니다.

def merge(d1, d2, merge_fn=lambda x,y:y):
    """
    Merges two dictionaries, non-destructively, combining 
    values on duplicate keys as defined by the optional merge
    function.  The default behavior replaces the values in d1
    with corresponding values in d2.  (There is no other generally
    applicable merge strategy, but often you'll have homogeneous 
    types in your dicts, so specifying a merge technique can be 
    valuable.)

    Examples:

    >>> d1
    {'a': 1, 'c': 3, 'b': 2}
    >>> merge(d1, d1)
    {'a': 1, 'c': 3, 'b': 2}
    >>> merge(d1, d1, lambda x,y: x+y)
    {'a': 2, 'c': 6, 'b': 4}

    """
    result = dict(d1)
    for k,v in d2.iteritems():
        if k in result:
            result[k] = merge_fn(result[k], v)
        else:
            result[k] = v
    return result

dict를 재귀적으로/심각하게 업데이트하다

def deepupdate(original, update):
    """
    Recursively update a dict.
    Subdict's won't be overwritten but also updated.
    """
    for key, value in original.iteritems(): 
        if key not in update:
            update[key] = value
        elif isinstance(value, dict):
            deepupdate(value, update[key]) 
    return update

데모:

pluto_original = {
    'name': 'Pluto',
    'details': {
        'tail': True,
        'color': 'orange'
    }
}

pluto_update = {
    'name': 'Pluutoo',
    'details': {
        'color': 'blue'
    }
}

print deepupdate(pluto_original, pluto_update)

출력:

{
    'name': 'Pluutoo',
    'details': {
        'color': 'blue',
        'tail': True
    }
}

편집해 주셔서 감사합니다.

Python 3.5(PEP 448)를 사용하면 다음과 같은 구문 옵션을 사용할 수 있습니다.

x = {'a': 1, 'b': 1}
y = {'a': 2, 'c': 2}
final = {**x, **y} 
final
# {'a': 2, 'b': 1, 'c': 2}

아니면 심지어

final = {'a': 1, 'b': 1, **x, **y}

Python 3.9에서는 PEP 584의 다음 예제와 함께 | 및 =도 사용합니다.

d = {'spam': 1, 'eggs': 2, 'cheese': 3}
e = {'cheese': 'cheddar', 'aardvark': 'Ethel'}
d | e
# {'spam': 1, 'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel'}
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = dict(x.items() + y.items())
print z

양쪽 사전('b')에 키가 있는 항목의 경우 키를 마지막으로 배치하여 출력에 표시되는 항목을 제어할 수 있습니다.

카피를 사용하지 않고 생각할 수 있는 최선의 버전은 다음과 같습니다.

from itertools import chain
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
dict(chain(x.iteritems(), y.iteritems()))

dict(x.items() + y.items()) n = copy(a); n.update(b)에서는).에서 Python 3을 합니다.iteritems()로로 합니다.items()2에서 3으로 나누다

개인적으로 이 버전이 가장 마음에 드는 이유는 내가 원하는 것을 하나의 기능 구문에서 꽤 잘 묘사하기 때문입니다.유일한 작은 문제는 y의 값이 x의 값보다 우선한다는 것을 완전히 명확히 알 수 없다는 것이지만, 나는 그것을 알아내는 것이 어렵지 않다고 생각한다.

제안서를 퍼포먼스 플롯으로 벤치마킹한 결과

x | y   # Python 3.9+

기존 제품과 함께 가장 빠른 해결책입니다.

{**x, **y}

그리고.

temp = x.copy()
temp.update(y)

여기에 이미지 설명 입력


플롯을 재현하는 코드:

from collections import ChainMap
from itertools import chain
import perfplot


def setup(n):
    x = dict(zip(range(n), range(n)))
    y = dict(zip(range(n, 2 * n), range(n, 2 * n)))
    return x, y


def copy_update(x, y):
    temp = x.copy()
    temp.update(y)
    return temp


def add_items(x, y):
    return dict(list(x.items()) + list(y.items()))


def curly_star(x, y):
    return {**x, **y}


def chain_map(x, y):
    return dict(ChainMap({}, y, x))


def itertools_chain(x, y):
    return dict(chain(x.items(), y.items()))


def python39_concat(x, y):
    return x | y


b = perfplot.bench(
    setup=setup,
    kernels=[
        copy_update,
        add_items,
        curly_star,
        chain_map,
        itertools_chain,
        python39_concat,
    ],
    labels=[
        "copy_update",
        "dict(list(x.items()) + list(y.items()))",
        "{**x, **y}",
        "chain_map",
        "itertools.chain",
        "x | y",
    ],
    n_range=[2 ** k for k in range(18)],
    xlabel="len(x), len(y)",
    equality_check=None,
)
b.save("out.png")
b.show()

이미 여러 번 질문에 답했지만 이 간단한 문제 해결 방법은 아직 나열되지 않았습니다.

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z4 = {}
z4.update(x)
z4.update(y)

이것은 위에서 언급한 z0과 사악한 z2만큼 빠르지만, 이해하고 변경하기 쉽습니다.

def dict_merge(a, b):
  c = a.copy()
  c.update(b)
  return c

new = dict_merge(old, extras)

이러한 의심스럽고 의심스러운 대답들 중에서, 이 빛나는 예는 평생 독재자 귀도 반 로섬이 지지한 파이썬의 딕트를 결합하는 유일한 유일한 좋은 방법이다.그 중 절반은 다른 사람이 제안했지만 함수에 넣지 않았다.

print dict_merge(
      {'color':'red', 'model':'Mini'},
      {'model':'Ferrari', 'owner':'Carl'})

다음과 같은 기능이 있습니다.

{'color': 'red', 'owner': 'Carl', 'model': 'Ferrari'}

피토닉이 되어라.이해력 사용:

z={k: v for d in [x,y] for k, v in d.items()}

>>> print z
{'a': 1, 'c': 11, 'b': 10}

람다가 사악하다고 생각되면 더 이상 읽지 마세요.요구에 따라 고속으로 메모리 효율이 뛰어난 솔루션을 다음 한 가지 표현으로 기술할 수 있습니다.

x = {'a':1, 'b':2}
y = {'b':10, 'c':11}
z = (lambda a, b: (lambda a_copy: a_copy.update(b) or a_copy)(a.copy()))(x, y)
print z
{'a': 1, 'c': 11, 'b': 10}
print x
{'a': 1, 'b': 2}

위와 같이 두 줄을 사용하거나 함수를 쓰는 것이 더 나은 방법일 것입니다.

itemsmethod는 더 이상 목록을 반환하지 않고 집합처럼 작동하는 보기를 반환합니다.이 경우 set union을 사용해야 합니다.그것은, 다음과 같이 연결되기 때문입니다.+다음 중 하나:

dict(x.items() | y.items())

2의 경우 python3은 "2.7" 입니다.viewitems대신 방법이 효과가 있어야 한다items:

dict(x.viewitems() | y.viewitems())

어쨌든 이 표기법은 (제목에서 알 수 있듯이) 연결이라기보다 집합적인 연합 조작이라고 생각하는 것이 더 자연스러운 것 같기 때문에 선호합니다.

편집:

파이썬 3에 대한 몇 가지 포인트가 더 있습니다. 번째로, 「」는 과 같습니다.dict(x, **y) 은 3 의 가 trick 에 포함되지 한 python 3y트링입입니니다

또한 Raymond Hettinger의 Chainmap 답변은 인수로 임의의 수의 dicts를 사용할 수 있기 때문에 매우 우아하지만 문서에서는 각 검색에 대한 모든 dict 목록을 순차적으로 살펴보는 것처럼 보입니다.

검색은 키가 발견될 때까지 기본 매핑을 연속적으로 검색합니다.

이 경우 응용 프로그램에서 검색 횟수가 많을 경우 속도가 느려질 수 있습니다.

In [1]: from collections import ChainMap
In [2]: from string import ascii_uppercase as up, ascii_lowercase as lo; x = dict(zip(lo, up)); y = dict(zip(up, lo))
In [3]: chainmap_dict = ChainMap(y, x)
In [4]: union_dict = dict(x.items() | y.items())
In [5]: timeit for k in union_dict: union_dict[k]
100000 loops, best of 3: 2.15 µs per loop
In [6]: timeit for k in chainmap_dict: chainmap_dict[k]
10000 loops, best of 3: 27.1 µs per loop

검색 속도가 약 1배 느립니다.저는 Chainmap의 팬이지만, 검색이 많은 곳에서는 실용성이 떨어집니다.

두 개의 사전

def union2(dict1, dict2):
    return dict(list(dict1.items()) + list(dict2.items()))

n 사전

def union(*dicts):
    return dict(itertools.chain.from_iterable(dct.items() for dct in dicts))

sum퍼포먼스가 나쁘다.https://mathieularose.com/how-not-to-flatten-a-list-of-lists-in-python/ 를 참조해 주세요.

순서를 유지하는 반복 툴을 사용한 심플한 솔루션(latter dicts가 우선)

# py2
from itertools import chain, imap
merge = lambda *args: dict(chain.from_iterable(imap(dict.iteritems, args)))

# py3
from itertools import chain
merge = lambda *args: dict(chain.from_iterable(map(dict.items, args)))

용도:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> merge(x, y)
{'a': 1, 'b': 10, 'c': 11}

>>> z = {'c': 3, 'd': 4}
>>> merge(x, y, z)
{'a': 1, 'b': 10, 'c': 3, 'd': 4}

Matthew의 답변에 대한 한 표현식 해결책으로 이어지는 남용:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = (lambda f=x.copy(): (f.update(y), f)[1])()
>>> z
{'a': 1, 'c': 11, 'b': 10}

이 한 가지 요.lambda이름을 바인딩하고, 람다의 일변수 제한을 재정의하기 위한 튜플입니다.마마얼

물론 복사하는 데 신경 쓰지 않는 경우에도 이 작업을 수행할 수 있습니다.

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = (x.update(y), x)[1]
>>> z
{'a': 1, 'b': 10, 'c': 11}

x ,

x.update(y) or x

심플하고 읽기 쉬우며 퍼포먼스도 뛰어납니다.아시잖아요 update() 반환하다None거짓 위의 '어느때보다 낫다'로 합니다.x 「」를 참조해 주세요.

라이브러리의 (「」등)..update()) (반환) 。None관례상 이런 패턴은 그런 것에도 통할 겁니다., 이 않는 dict 에는 dict를 사용합니다.or왼쪽 피연산자를 반환할 수 있지만 원하는 피연산자가 아닐 수 있습니다.대신 태플 디스플레이와 인덱스를 사용할 수 있습니다.태플 디스플레이와 인덱스는 첫 번째 요소의 평가 결과에 관계없이 작동합니다(예쁘지는 않지만).

(x.update(y), x)[-1]

★★★가x변수에서 사용할 수 있습니다.lambda할당문을 사용하지 않고 로컬로 만듭니다. '아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아lambda기능적 언어에서 일반적인 기술인 let 표현으로 사용되지만 비음절적일 수 있습니다.

(lambda x: x.update(y) or x)({'a': 1, 'b': 2})

새로운 바다코끼리의 연산자(Python 3.8+만 해당)를 사용하는 것과 크게 다르지 않지만,

(x := {'a': 1, 'b': 2}).update(y) or x

특히 기본 인수를 사용하는 경우:

(lambda x={'a': 1, 'b': 2}: x.update(y) or x)()

복사하고 싶다면 PEP 584 스타일x | y3.9+에서 가장 피토닉합니다.이전 버전을 지원해야 하는 경우 PEP 448 스타일{**x, **y}3.5+가 가장 간단합니다.그러나 Python 버전(더 오래된 버전)에서 사용할 수 없는 경우 let expression pattern도 여기에서 사용할 수 있습니다.

(lambda z=x.copy(): z.update(y) or z)()

은 물론 은)에 합니다.)(z := x.copy()).update(y) or zPython 버전이 새로운 버전이라면 PEP 448 스타일을 사용할 수 있습니다.)

여기와 다른 곳에서 아이디어를 끌어다 보니 다음과 같은 기능을 이해했습니다.

def merge(*dicts, **kv): 
      return { k:v for d in list(dicts) + [kv] for k,v in d.items() }

사용방법(python 3에서 테스트 완료):

assert (merge({1:11,'a':'aaa'},{1:99, 'b':'bbb'},foo='bar')==\
    {1: 99, 'foo': 'bar', 'b': 'bbb', 'a': 'aaa'})

assert (merge(foo='bar')=={'foo': 'bar'})

assert (merge({1:11},{1:99},foo='bar',baz='quux')==\
    {1: 99, 'foo': 'bar', 'baz':'quux'})

assert (merge({1:11},{1:99})=={1: 99})

대신 람다를 사용하셔도 됩니다.

Python 3.9의 새로운 기능: union 연산자 사용(|dict와 유사하다sets:

>>> d = {'a': 1, 'b': 2}
>>> e = {'a': 9, 'c': 3}
>>> d | e
{'a': 9, 'b': 2, 'c': 3}

일치하는 키의 경우 오른쪽이 우선합니다.

이 방법도 유효합니다.|=dict★★★★★★★★★★★★★★★★★★:

>>> e |= d    # e = e | d
>>> e
{'a': 1, 'c': 3, 'b': 2}

도 안 돼.update이치노
간단한 도우미 기능을 사용하여 문제를 해결합니다.

def merge(dict1,*dicts):
    for dict2 in dicts:
        dict1.update(dict2)
    return dict1

예:

merge(dict1,dict2)
merge(dict1,dict2,dict3)
merge(dict1,dict2,dict3,dict4)
merge({},dict1,dict2)  # this one returns a new copy

(Python 2.7*의 경우만 해당. Python 3*의 경우 더 간단한 솔루션이 있습니다.

표준 라이브러리 모듈 가져오기를 거부하지 않는 경우 다음을 수행할 수 있습니다.

from functools import reduce

def merge_dicts(*dicts):
    return reduce(lambda a, d: a.update(d) or a, dicts, {})

(the)or a을 품다lambda은 '이유'이기 때문입니다.dict.update 반환하다None★★★★★★★★★★★★★★★★」

지금까지의 솔루션 리스트의 문제는, 통합 사전에서는, 키 「b」의 값이 10이지만, 제 생각에는 12가 될 것 같습니다.그런 의미에서 다음 사항을 제시하겠습니다.

import timeit

n=100000
su = """
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
"""

def timeMerge(f,su,niter):
    print "{:4f} sec for: {:30s}".format(timeit.Timer(f,setup=su).timeit(n),f)

timeMerge("dict(x, **y)",su,n)
timeMerge("x.update(y)",su,n)
timeMerge("dict(x.items() + y.items())",su,n)
timeMerge("for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k] ",su,n)

#confirm for loop adds b entries together
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k]
print "confirm b elements are added:",x

결과:

0.049465 sec for: dict(x, **y)
0.033729 sec for: x.update(y)                   
0.150380 sec for: dict(x.items() + y.items())   
0.083120 sec for: for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k]

confirm b elements are added: {'a': 1, 'c': 11, 'b': 12}
from collections import Counter
dict1 = {'a':1, 'b': 2}
dict2 = {'b':10, 'c': 11}
result = dict(Counter(dict1) + Counter(dict2))

이것으로 당신의 문제가 해결될 것입니다.

PEP 572: Assignment Expressions 덕분에 Python 3.8이 출시될 때(2019년 10월 20일로 예정됨) 새로운 옵션이 제공됩니다.새 할당 식 연산자:=에서는 allows 、 of 、 allows 、 の of of of of of of of of of의 할 수 .copy하여, 「」를 호출합니다.update조합된 코드를 2개의 문이 아닌 단일 표현으로 남겨두면 다음과 같이 변경됩니다.

newdict = dict1.copy()
newdict.update(dict2)

대상:

(newdict := dict1.copy()).update(dict2)

결과dict하셨습니다).dict되어 에 됩니다.newdict라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라 라의 함 할 수 없다' 라고 할 수 myfunc((newdict := dict1.copy()).update(dict2))), 그럼 추가만 하면 됩니다.or newdict까지 (언제부터)updateNonenewdict(이 (이 식에 따라):

(newdict := dict1.copy()).update(dict2) or newdict

중요한 경고:일반적으로 이 접근방식은 다음 사항을 위해 권장하지 않습니다.

newdict = {**dict1, **dict2}

(처음부터 일반적인 언팩을 알고 있는 사람에게는) 언팩 방식이 더 명확합니다.따라서 함수에 즉시 전달되거나 함수에 포함된 임시 구성 시 결과 이름이 전혀 필요하지 않습니다.list/tuple는하므로 거의 더 (CPython의 경우

newdict = {}
newdict.update(dict1)
newdict.update(dict2)

콘크리트를 되었습니다.dict하지 않습니다(서 API는 '/'로 되어 있습니다).(newdict := dict1.copy()).update(dict2)동작은 원래 2라인과 동일하며 메서드의 동적 룩업/바인딩/호출과 함께 개별 스텝으로 작업을 수행합니다.

3개의 3개의 3개의 3개의 3개의 3개의 3개의 의 3개의 3개의 3개의 3개의 3개의 3개의 3개의 3개의 3개의 3개의 3개의 3개의 3개의 3개의 3개의 3개의 3개의 3개의 3개의 3개의 3개의 3개의 3개의 3개의 3개의 3개의 3개의 3개의 3개의dict명백하다:s는 명백하다.

 newdict = {**dict1, **dict2, **dict3}

여기서 할당식을 사용하는 것은 그렇게 확장되지 않습니다.최대한 가까운 값은 다음과 같습니다.

 (newdict := dict1.copy()).update(dict2), newdict.update(dict3)

임시 경우None 각 '의 테스트에서는 ''의None★★★★

 (newdict := dict1.copy()).update(dict2) or newdict.update(dict3)

인가 하면, 훨씬 추하고, 더 인 것( 것, 일시적 것, 일시적 것, 일시적 것, 또는 일시적 것)을 포함한다.tupleNone s의 콤마 없는 .update의 »Noneor★★★★★★★★★★★★★★★★★★」

할당식 접근법의 유일한 실질적인 이점은 다음과 같은 경우 발생합니다.

  1. 를 모두 처리해야 하는 범용 코드가 있다(양쪽 모두 지원).copy ★★★★★★★★★★★★★★★★★」update
  2. dict와 같은 임의의 오브젝트를 수신하는 것뿐만 아니라dict 자체로 왼쪽의 유형과 의미를 보존해야 한다(단순한 것으로 끝나는 것이 아니라).dict) 。myspecialdict({**speciala, **specialb})인 임시로 할 수 .dict및 if , 「」myspecialdictdict보존할 수 없다(예: 일반)dict이제 키의 첫 번째 출현을 기반으로 한 순서와 키의 마지막 출현을 기준으로 한 값을 유지하게 되었습니다.키를 마지막으로 출현한 순서에 따라 순서를 유지하여 값을 갱신하면 마지막까지 이동할 수 있습니다).그러면 의미론이 틀리게 됩니다.할당식 버전은 명명된 메서드(적절하게 동작하기 위해 오버로드된 것으로 추정됨)를 사용하기 때문에,dict(만약에) 하지 않는 한dict1 있었다dict에서는, 일시적이지 않게 원래의 타입(및 원래의 타입의 의미론)을 보존합니다.

이는 단일 딕트 이해로 수행할 수 있습니다.

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> { key: y[key] if key in y else x[key]
      for key in set(x) + set(y)
    }

내가 보기에 '단일 표현' 부분에 대한 가장 좋은 답은 추가 기능이 필요하지 않고 짧기 때문입니다.

언급URL : https://stackoverflow.com/questions/38987/how-do-i-merge-two-dictionaries-in-a-single-expression-in-python

반응형