Programing

두 개의 dicts를 결합하는 파이썬적인 방법이 있습니까 (둘 다에 나타나는 키 값 추가)?

lottogame 2020. 2. 16. 19:12
반응형

두 개의 dicts를 결합하는 파이썬적인 방법이 있습니까 (둘 다에 나타나는 키 값 추가)?


예를 들어 두 가지 dicts가 있습니다.

Dict A: {'a': 1, 'b': 2, 'c': 3}
Dict B: {'b': 3, 'c': 4, 'd': 5}

결과가 다음과 같이 두 가지 dicts를 '결합'하는 pythonic 방법이 필요합니다.

{'a': 1, 'b': 5, 'c': 7, 'd': 5}

즉, 키가 두 개의 dicts에 나타나면 값을 추가하고 하나의 dict에만 나타나면 값을 유지하십시오.


사용 collections.Counter:

>>> from collections import Counter
>>> A = Counter({'a':1, 'b':2, 'c':3})
>>> B = Counter({'b':3, 'c':4, 'd':5})
>>> A + B
Counter({'c': 7, 'b': 5, 'd': 5, 'a': 1})

카운터는 기본적으로의 하위 클래스 dict이므로 키와 값을 반복하는 등 일반적으로 해당 유형으로 수행하는 다른 모든 작업을 수행 할 수 있습니다.


숫자가 아닌 값에도 적용되는보다 일반적인 솔루션 :

a = {'a': 'foo', 'b':'bar', 'c': 'baz'}
b = {'a': 'spam', 'c':'ham', 'x': 'blah'}

r = dict(a.items() + b.items() +
    [(k, a[k] + b[k]) for k in set(b) & set(a)])

또는 더 일반적인 :

def combine_dicts(a, b, op=operator.add):
    return dict(a.items() + b.items() +
        [(k, op(a[k], b[k])) for k in set(b) & set(a)])

예를 들면 다음과 같습니다.

>>> a = {'a': 2, 'b':3, 'c':4}
>>> b = {'a': 5, 'c':6, 'x':7}

>>> import operator
>>> print combine_dicts(a, b, operator.mul)
{'a': 10, 'x': 7, 'c': 24, 'b': 3}

>>> A = {'a':1, 'b':2, 'c':3}
>>> B = {'b':3, 'c':4, 'd':5}
>>> c = {x: A.get(x, 0) + B.get(x, 0) for x in set(A).union(B)}
>>> print(c)

{'a': 1, 'c': 7, 'b': 5, 'd': 5}

소개 : (아마도) 최상의 솔루션이 있습니다. 그러나 당신은 그것을 알고 기억해야하며 때로는 파이썬 버전이 너무 오래되지 않았거나 문제가 될 수 있기를 바랍니다.

그런 다음 가장 '해킹 된'솔루션이 있습니다. 그것들은 위대하고 짧지 만 때로는 이해하고 읽고 기억하기가 어렵습니다.

그러나 바퀴를 재발 명하려는 대안이 있습니다. -왜 바퀴를 재발 명합니까? -일반적으로 학습하기에 좋은 방법이기 때문에 (때로는 이미 존재하는 도구가 원하는 것을 정확하게 수행하지 않거나 원하는 방식으로 수행하지 않기 때문에) 알고 있거나 모르는 경우 가장 쉬운 방법이기 때문입니다. 문제에 대한 완벽한 도구를 기억하지 마십시오.

그래서 나는 모듈 에서 Counter클래스 의 바퀴를 collections(부분적으로) 재발 명 할 것을 제안합니다 .

class MyDict(dict):
    def __add__(self, oth):
        r = self.copy()

        try:
            for key, val in oth.items():
                if key in r:
                    r[key] += val  # You can custom it here
                else:
                    r[key] = val
        except AttributeError:  # In case oth isn't a dict
            return NotImplemented  # The convention when a case isn't handled

        return r

a = MyDict({'a':1, 'b':2, 'c':3})
b = MyDict({'b':3, 'c':4, 'd':5})

print(a+b)  # Output {'a':1, 'b': 5, 'c': 7, 'd': 5}

아마도 그것을 구현하는 다른 방법이있을 것입니다.이를 수행하는 도구가 이미 있지만 일이 기본적으로 어떻게 작동하는지 시각화하는 것이 좋습니다.


myDict = {}
for k in itertools.chain(A.keys(), B.keys()):
    myDict[k] = A.get(k, 0)+B.get(k, 0)

추가 수입품없는 분!

그것들은 EAFP (권한보다 용서를 구하는 것이 더 쉽다) 라는 pythonic 표준 입니다. 아래 코드는 해당 파이썬 표준을 기반으로합니다 .

# The A and B dictionaries
A = {'a': 1, 'b': 2, 'c': 3}
B = {'b': 3, 'c': 4, 'd': 5}

# The final dictionary. Will contain the final outputs.
newdict = {}

# Make sure every key of A and B get into the final dictionary 'newdict'.
newdict.update(A)
newdict.update(B)

# Iterate through each key of A.
for i in A.keys():

    # If same key exist on B, its values from A and B will add together and
    # get included in the final dictionary 'newdict'.
    try:
        addition = A[i] + B[i]
        newdict[i] = addition

    # If current key does not exist in dictionary B, it will give a KeyError,
    # catch it and continue looping.
    except KeyError:
        continue

편집 : 그의 개선 제안에 대해 jerzyk 에게 감사드립니다 .


확실히 Counter()s를 합산하는 것은 그러한 경우에 가장 파이썬적인 방법이지만 양의 값을 얻는 경우에만 가능합니다 . 다음은 예이며 사전 에서의 값을 c무시한 후 결과 가 없습니다 .cB

In [1]: from collections import Counter

In [2]: A = Counter({'a':1, 'b':2, 'c':3})

In [3]: B = Counter({'b':3, 'c':-4, 'd':5})

In [4]: A + B
Out[4]: Counter({'d': 5, 'b': 5, 'a': 1})

왜냐하면 Counters는 주로 양의 정수로 작동하여 연속 카운트를 나타내도록 설계 되었기 때문입니다 (음수는 의미가 없음). 그러나 이러한 사용 사례를 돕기 위해 Python은 최소 범위 및 유형 제한을 다음과 같이 문서화합니다.

  • Counter 클래스 자체는 키와 값에 제한이없는 사전 서브 클래스입니다. 값은 개수를 나타내는 숫자이지만 값 필드에 아무 것도 저장할 수 있습니다.
  • most_common()방법은 값을 주문할 수 있어야합니다.
  • 와 같은 내부 작업의 c[key] += 1경우 값 유형은 더하기 및 빼기 만 지원하면됩니다. 따라서 분수, 부동 소수점 및 소수가 작동하고 음수 값이 지원됩니다. 동일한도 마찬가지이다 update()하고 subtract()이는 입력 및 출력 모두 마이너스 제로 값을 허용한다.
  • 다중 집합 방법은 양수 값을 가진 사용 사례에 대해서만 설계되었습니다. 입력은 음수이거나 0 일 수 있지만 양수 값의 출력 만 작성됩니다. 유형 제한은 없지만 값 유형은 더하기, 빼기 및 비교를 지원해야합니다.
  • elements()방법에는 정수 카운트가 필요합니다. 0과 음수를 무시합니다.

따라서 카운터를 합산 한 후 그 문제를 해결 Counter.update하기 위해 원하는 출력을 얻기 위해 사용할 수 있습니다 . 그것은 작동 dict.update()하지만 카운트 대신에 카운트를 추가합니다.

In [24]: A.update(B)

In [25]: A
Out[25]: Counter({'d': 5, 'b': 5, 'a': 1, 'c': -1})

import itertools
import collections

dictA = {'a':1, 'b':2, 'c':3}
dictB = {'b':3, 'c':4, 'd':5}

new_dict = collections.defaultdict(int)
# use dict.items() instead of dict.iteritems() for Python3
for k, v in itertools.chain(dictA.iteritems(), dictB.iteritems()):
    new_dict[k] += v

print dict(new_dict)

# OUTPUT
{'a': 1, 'c': 7, 'b': 5, 'd': 5}

또는

대안은 @Martijn이 위에서 언급했듯이 Counter를 사용할 수 있습니다.


보다 일반적이고 확장 가능한 방법으로 mergedict를 확인 하십시오 . singledispatch유형에 따라 값을 사용 하고 병합 할 수 있습니다.

예:

from mergedict import MergeDict

class SumDict(MergeDict):
    @MergeDict.dispatch(int)
    def merge_int(this, other):
        return this + other

d2 = SumDict({'a': 1, 'b': 'one'})
d2.merge({'a':2, 'b': 'two'})

assert d2 == {'a': 3, 'b': 'two'}

Python 3.5에서 : 병합 및 합산

의견의 의미를 완전히 얻지 못했다는 의견에서 @tokeinizer_fsj 덕분에 (추가는 두 개의 사전에서 다른 키를 추가하는 것을 의미한다고 생각했습니다. 대신 일반적인 키 값을 의미했습니다. 합계해야합니다). 그래서 병합하기 전에 루프를 추가하여 두 번째 사전에 공통 키의 합계가 포함되도록했습니다. 마지막 사전은 새 사전에서 두 값을 병합 한 결과 값이 지속되는 사전이므로 문제가 해결됩니다. 이 솔루션은 python 3.5 및 이후 버전에서 유효합니다.

a = {
    "a": 1,
    "b": 2,
    "c": 3
}

b = {
    "a": 2,
    "b": 3,
    "d": 5
}

# Python 3.5

for key in b:
    if key in a:
        b[key] = b[key] + a[key]

c = {**a, **b}
print(c)

>>> c
{'a': 3, 'b': 5, 'c': 3, 'd': 5}

재사용 가능한 코드

a = {'a': 1, 'b': 2, 'c': 3}
b = {'b': 3, 'c': 4, 'd': 5}


def mergsum(a, b):
    for k in b:
        if k in a:
            b[k] = b[k] + a[k]
    c = {**a, **b}
    return c


print(mergsum(a, b))

또한 a.update( b )2 배 더 빠릅니다.a + b

from collections import Counter
a = Counter({'menu': 20, 'good': 15, 'happy': 10, 'bar': 5})
b = Counter({'menu': 1, 'good': 1, 'bar': 3})

%timeit a + b;
## 100000 loops, best of 3: 8.62 µs per loop
## The slowest run took 4.04 times longer than the fastest. This could mean that an intermediate result is being cached.

%timeit a.update(b)
## 100000 loops, best of 3: 4.51 µs per loop

def merge_with(f, xs, ys):
    xs = a_copy_of(xs) # dict(xs), maybe generalizable?
    for (y, v) in ys.iteritems():
        xs[y] = v if y not in xs else f(xs[x], v)

merge_with((lambda x, y: x + y), A, B)

이것을 쉽게 일반화 할 수 있습니다 :

def merge_dicts(f, *dicts):
    result = {}
    for d in dicts:
        for (k, v) in d.iteritems():
            result[k] = v if k not in result else f(result[k], v)

그런 다음 임의의 수의 dict가 필요할 수 있습니다.


이것은 +=값에 적용 할 수있는 두 개의 사전을 병합하기위한 간단한 솔루션입니다 . 사전을 한 번만 반복해야합니다.

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

dicts = [{'b':3, 'c':4, 'd':5},
         {'c':9, 'a':9, 'd':9}]

def merge_dicts(merged,mergedfrom):
    for k,v in mergedfrom.items():
        if k in merged:
            merged[k] += v
        else:
            merged[k] = v
    return merged

for dct in dicts:
    a = merge_dicts(a,dct)
print (a)
#{'c': 16, 'b': 5, 'd': 14, 'a': 10}

다른 모듈이나 라이브러리없이 세 줄의 a, b, c를 한 줄에 병합

우리가 세 가지 dicts를 가지고 있다면

a = {"a":9}
b = {"b":7}
c = {'b': 2, 'd': 90}

한 줄로 모두 병합하고 다음을 사용하여 dict 객체를 반환하십시오.

c = dict(a.items() + b.items() + c.items())

귀국

{'a': 9, 'b': 2, 'd': 90}

이 솔루션은 사용하기 쉽고 일반 사전으로 사용되지만 합계 기능을 사용할 수 있습니다.

class SumDict(dict):
    def __add__(self, y):
        return {x: self.get(x, 0) + y.get(x, 0) for x in set(self).union(y)}

A = SumDict({'a': 1, 'c': 2})
B = SumDict({'b': 3, 'c': 4})  # Also works: B = {'b': 3, 'c': 4}
print(A + B)  # OUTPUT {'a': 1, 'b': 3, 'c': 6}

위의 솔루션은 적은 수의 시나리오에 적합합니다 Counter. 그래도 큰 목록이 있다면 다음과 같은 것이 훨씬 좋습니다.

from collections import Counter

A = Counter({'a':1, 'b':2, 'c':3})
B = Counter({'b':3, 'c':4, 'd':5}) 
C = Counter({'a': 5, 'e':3})
list_of_counts = [A, B, C]

total = sum(list_of_counts, Counter())

print(total)
# Counter({'c': 7, 'a': 6, 'b': 5, 'd': 5, 'e': 3})

위의 솔루션은 본질적으로 Counters를 합산합니다 .

total = Counter()
for count in list_of_counts:
    total += count
print(total)
# Counter({'c': 7, 'a': 6, 'b': 5, 'd': 5, 'e': 3})

이것은 똑같은 일을하지만 항상 그것이 실제로 무엇을하고 있는지 보는 것이 도움이된다고 생각합니다.


는 어때:

def dict_merge_and_sum( d1, d2 ):
    ret = d1
    ret.update({ k:v + d2[k] for k,v in d1.items() if k in d2 })
    ret.update({ k:v for k,v in d2.items() if k not in d1 })
    return ret

A = {'a': 1, 'b': 2, 'c': 3}
B = {'b': 3, 'c': 4, 'd': 5}

print( dict_merge_and_sum( A, B ) )

산출:

{'d': 5, 'a': 1, 'c': 7, 'b': 5}

사용하는 가장 좋은 방법은 dict ()입니다.

A = {'a':1, 'b':2, 'c':3}
B = {'b':3, 'c':4, 'd':5}
Merged = dict(A, **B)
Merged == {'a':1, 'b':3, 'c':3, 'd':5}

참고 URL : https://stackoverflow.com/questions/11011756/is-there-any-pythonic-way-to-combine-two-dicts-adding-values-for-keys-that-appe



반응형