파이썬에서 사전을 어떻게 병합합니까?


91
d3 = dict(d1, **d2)

나는 이것이 사전을 병합한다는 것을 이해합니다. 그러나 그것은 독특합니까? d1에 d2와 동일한 키가 있지만 값이 다른 경우 어떻게됩니까? d1과 d2를 병합하고 싶지만 중복 키가 있으면 d1이 우선합니다.


9
이 트릭은 **모든 키 d2가 문자열이 아닌 경우 키워드 인수 전달 의 남용으로 간주 됩니다. 의 모든 키 d2가 문자열이 아닌 경우 Python 3.2 및 Jython, IronPython 및 PyPy와 같은 대체 Python 구현에서는 실패합니다. 예를 들어 mail.python.org/pipermail/python-dev/2010-April/099459.html을 참조하십시오 .
Mark Dickinson

답변:


154

.update()원본이 d2더 이상 필요하지 않은 경우 방법을 사용할 수 있습니다 .

다른 키 / 값 쌍으로 사전을 업데이트하고 기존 키를 덮어 씁니다 . 반환 None.

예 :

>>> d1 = {'a': 1, 'b': 2} 
>>> d2 = {'b': 1, 'c': 3}
>>> d2.update(d1)
>>> d2
{'a': 1, 'c': 3, 'b': 2}

최신 정보:

물론 병합 된 새 사전을 만들기 위해 먼저 사전을 복사 할 수 있습니다. 이것은 필요하거나 필요하지 않을 수 있습니다. 사전에 복합 객체 (목록 또는 클래스 인스턴스와 같은 다른 객체를 포함하는 객체)가있는 copy.deepcopy경우에도 고려되어야합니다.


1
이 경우 충돌하는 키가 발견되면 d1 요소가 올바르게 우선 순위를 가져야합니다
Trey Hunner

그래도 필요한 경우 사본을 만드십시오. d3 = d2.copy () d3.update (d1)하지만 d1 + d2가 언어에 추가되는 것을보고 싶습니다.

4
d1 + d2는 하나의 사전이 충돌 중에 우선 순위를 가져야하기 때문에 문제가되고 어떤 사전이 특히 명확하지 않습니다.
rjh

d1 + d2는 파이썬이 멀티 맵을 얻는 경우에만 구현됩니다. 그렇지 않으면 사용자에 대한 모호함이 8 바이트 타이핑 이득을 얻기에는 너무 혼란 스럽습니다.
Nick Bastin

이 예에서 사전에 개체가 : isinstance(int, object) is True아직 deepcopy필요하지 않는 것 같습니다.
안토니 Hatchkins

43

Python2에서는

d1={'a':1,'b':2}
d2={'a':10,'c':3}

d1은 d2를 재정의합니다.

dict(d2,**d1)
# {'a': 1, 'c': 3, 'b': 2}

d2는 d1을 재정의합니다.

dict(d1,**d2)
# {'a': 10, 'c': 3, 'b': 2}

이 동작은 단순히 구현의 우연이 아닙니다. 문서에서 보장 됩니다 .

키가 위치 인수와 키워드 인수 모두에 지정되면 키워드와 연관된 값이 사전에 유지됩니다.


3
Python 3.2와 현재 버전의 Jython, PyPy 및 IronPython에서 예제가 실패 (TypeError 생성)됩니다. 이러한 버전의 Python의 경우 **표기법 과 함께 dict를 전달할 때 해당 dict의 모든 키는 문자열이어야합니다. 자세한 내용은 mail.python.org/pipermail/python-dev/2010-April/099427.html 에서 시작하는 python-dev 스레드를 참조하세요 .
Mark Dickinson

@Mark : 고마워요. 비 CPython 구현과 호환되도록 코드를 편집했습니다.
unutbu

3
키가 문자열과 숫자의 튜플이면 실패합니다. 예를 들어. d1 = {(1, 'a') : 1, (1, 'b') : 0,} d2 = {(1, 'a') : 1, (2, 'b') : 2, (2, 'A') : 1,}
MySchizoBuddy

압축 풀기 구문과 관련하여 Python 3.5에서 예정된 변경 사항 은 이 게시물 을 참조하십시오 .
요안 Filippidis

나는 그것이 d = dict(**d1, **d2)효과 가 있다고 말하려고 했지만 @IoannisFilippidis가 그들의 의견에서 언급 한 것입니다. 아마도 여기에 스 니펫을 포함하는 것이 더 명확했을 것이므로 여기에 있습니다.
dwanderson

14

d1충돌에 우선 순위 를 두려면 다음 을 수행하십시오.

d3 = d2.copy()
d3.update(d1)

그렇지 않으면 반전 d2d1.


1

내 해결책은 병합 기능 을 정의하는 것입니다. 정교하지 않고 한 줄만 들었습니다. 다음은 Python 3의 코드입니다.

from functools import reduce
from operator import or_

def merge(*dicts):
    return { k: reduce(lambda d, x: x.get(k, d), dicts, None) for k in reduce(or_, map(lambda x: x.keys(), dicts), set()) }

테스트

>>> d = {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
>>> d_letters = {0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'}
>>> merge(d, d_letters)
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'}
>>> merge(d_letters, d)
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'}
>>> merge(d)
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
>>> merge(d_letters)
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'}
>>> merge()
{}

임의의 수의 사전 인수에 대해 작동합니다. 해당 사전에 중복 키가 있으면 인수 목록에서 가장 오른쪽 사전의 키가 우선합니다.


1
.update호출 ( merged={}뒤에 for d in dict: merged.update(d))이있는 단순 루프는 더 짧고 읽기 쉽고 효율적입니다.
Mark Dickinson

1
또는 reducelambdas 를 정말로 사용 하고 싶다면 return reduce(lambda x, y: x.update(y) or x, dicts, {})어떻습니까?
Mark Dickinson

1
쉘에서 코드를 시험 해보고 올바른지 확인할 수 있습니다. 내가하려는 것은 동일한 기능을 가진 다양한 사전 인수를 취할 수있는 함수를 작성하는 것입니다. 항상 None을 반환하기 때문에 람다에서 x.update (y)를 사용하지 않는 것이 좋습니다 . 그리고 다양한 수의 사전 인수를 취하고 제공된 함수로 중복 키를 처리 하는보다 일반적인 함수 merge_with 를 작성하려고 합니다. 완료되면 솔루션이 더 관련성이 높은 다른 스레드에 게시하겠습니다.
Lei Zhao

여기 에 더 일반적인 솔루션을 작성한 링크 가 있습니다. 환영합니다.
Lei Zhao


1

에서 시작 Python 3.9하여 연산자 |는 두 사전에서 병합 된 키와 값으로 새 사전을 만듭니다.

# d1 = { 'a': 1, 'b': 2 }
# d2 = { 'b': 1, 'c': 3 }
d3 = d2 | d1
# d3: {'b': 2, 'c': 3, 'a': 1}

이:

병합 된 키와 d2 및 d1 값을 사용하여 새 사전 d3을 만듭니다. d2와 d1이 키를 공유 할 때 d1의 값이 우선합니다.


또한 |=d1 값에 우선 순위를두고 d1 in을 병합하여 d2를 수정 하는 연산자에 유의하십시오 .

# d1 = { 'a': 1, 'b': 2 }
# d2 = { 'b': 1, 'c': 3 }
d2 |= d1
# d2: {'b': 2, 'c': 3, 'a': 1}


0

위에서 언급했듯이 사용하는 d2.update(d1)것이 가장 좋은 방법이며 d2필요한 경우 먼저 복사 할 수도 있습니다.

그러나 dict(d1, **d2)키워드 인수가 문자열이어야하므로 일반적으로 사전을 병합 하는 것이 실제로는 나쁜 방법 이라는 점을 지적하고 싶습니다 . 따라서 다음 dict과 같은 경우 실패합니다 .

{
  1: 'foo',
  2: 'bar'
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.