source

일치하는 키에서 값을 수집하여 딕트를 병합하는 방법은 무엇입니까?

factcode 2023. 7. 18. 22:00
반응형

일치하는 키에서 값을 수집하여 딕트를 병합하는 방법은 무엇입니까?

다음과 같은 딕트(또는 키-값 쌍의 시퀀스)가 여러 개 있습니다.

d1 = {key1: x1, key2: y1}
d2 = {key1: x2, key2: y2}

새로운 딕트로서 어떻게 효율적으로 이런 결과를 얻을 수 있습니까?

d = {key1: (x1, x2), key2: (y1, y2)}

참고 항목:어떻게 파이썬에서 중복 키로 사전을 만들있습니까?

다음은 임의의 양의 사전을 처리하는 일반적인 솔루션으로, 일부 사전에만 키가 있는 경우입니다.

from collections import defaultdict

d1 = {1: 2, 3: 4}
d2 = {1: 6, 3: 7}

dd = defaultdict(list)

for d in (d1, d2): # you can list as many input dicts as you want here
    for key, value in d.items():
        dd[key].append(value)
    
print(dd) # result: defaultdict(<type 'list'>, {1: [2, 6], 3: [4, 7]})

모든 키가 모든 딕트에 항상 존재한다고 가정합니다.

ds = [d1, d2]
d = {}
for k in d1.iterkeys():
    d[k] = tuple(d[k] for d in ds)

참고: Python 3.x에서는 아래 코드를 사용합니다.

ds = [d1, d2]
d = {}
for k in d1.keys():
  d[k] = tuple(d[k] for d in ds)

dic에 numpy 배열이 포함된 경우:

ds = [d1, d2]
d = {}
for k in d1.keys():
  d[k] = np.concatenate(list(d[k] for d in ds))

이 기능은 두 사전의 키가 다른 경우에도 두 개의 딕트를 병합합니다.

def combine_dict(d1, d2):
    return {
        k: tuple(d[k] for d in (d1, d2) if k in d)
        for k in set(d1.keys()) | set(d2.keys())
    }

예:

d1 = {
    'a': 1,
    'b': 2,
}
d2 = {
    'b': 'boat',
    'c': 'car',
    'd': 'donkey',
}
combine_dict(d1, d2)
# Returns: {
#    'a': (1,),
#    'b': (2, 'boat'),
#    'c': ('car',),
#    'd': ('donkey'),
# }
dict1 = {'m': 2, 'n': 4}
dict2 = {'n': 3, 'm': 1}

키의 순서가 동일한지 확인합니다.

dict2_sorted = {i:dict2[i] for i in dict1.keys()}

keys = dict1.keys()
values = zip(dict1.values(), dict2_sorted.values())
dictionary = dict(zip(keys, values))

제공:

{'m': (2, 1), 'n': (4, 3)}

만약 당신이 d1과 d2만 가지고 있다면,

from collections import defaultdict

d = defaultdict(list)
for a, b in d1.items() + d2.items():
    d[a].append(b)

다음은 두 사전에 동일한 키가 없는 경우에도 사용할 수 있는 한 가지 방법입니다.

d1 = {'a':'test','b':'btest','d':'dreg'}
d2 = {'a':'cool','b':'main','c':'clear'}

d = {}

for key in set(list(d1.keys()) + list(d2.keys())):
    try:
        d.setdefault(key,[]).append(d1[key])        
    except KeyError:
        pass

    try:
        d.setdefault(key,[]).append(d2[key])          
    except KeyError:
        pass

print(d)

이렇게 하면 다음과 같은 입력이 생성됩니다.

{'a': ['test', 'cool'], 'c': ['clear'], 'b': ['btest', 'main'], 'd': ['dreg']}

사전 계산된 키 사용

def merge(dicts):
    # First, figure out which keys are present.
    keys = set().union(*dicts)
    # Build a dict with those keys, using a list comprehension to
    # pull the values from the source dicts.
    return {
        k: [d[k] for d in dicts if k in d]
        for k in keys
    }

이것은 기본적으로 입력 딕트 목록에 대해 일반화된 플럭스의 답변입니다.

set().union은 모든 합니다.trick 모든소사전서키에의집만작결동들합다니어을합합은스▁trick다작니▁in동▁by합trick▁making▁works▁keys만▁of어들▁a은을aries▁diction.union ▁onset는 빈합니다)는수의 인수를 각할 수 , 반복 가능한 할 수 . 그리고 그것은 다른 반복 가능성을 허용할 수 있습니다(다른 반복 가능성은 필요하지 않습니다).setarguments) - .s for the unique elements for the 인수) - 인위반모고요찾유소다습니를든.한 번 이상 반복된 이후로dict키를산여전수있습다니할로 될 수 .union방법.

한 것으로 할 수 : 모입력 키동것알한경려우진로, 이를단수있습다니할화순의으.keys코딩(중 이 가능하며, 하드또코(딩될입중하추서론있며으수)에나력,if목록에서 체크 인 이해가 불필요해집니다.

def merge(dicts):
    return {
        k: [d[k] for d in dicts]
        for k in dicts[0].keys()
    }

이것은 blub의 답변과 유사하지만 최종 결과를 만들기 위해 명시적 루프가 아닌 받아쓰기 이해를 사용합니다.

우리는 또한 Mahdi Ghelichi의 대답과 같은 것을 시도할 수 있습니다.

def merge(dicts):
    values = zip(*(d.values() for d in ds))
    return dict(zip(dicts[0].keys(), values))

이것은 Python 3.5 이하에서 작동해야 합니다. 동일한 키를 가진 딕트프로그램을 동일하게 실행하는 동안 동일한 순서로 저장합니다(프로그램을 다시 실행하면 다른 순서를 얻을 수 있지만 여전히 일관성 있는 순서로).3.6 이상에서는 사전이 삽입 순서를 유지합니다(3.7 이상에서는 삽입 순서만 보장됨).따라서 입력 딕트는 동일한 키를 다른 순서로 가질 수 있으며, 이는 첫 번째 키를 유발할 수 있습니다.zip잘못된 값을 결합합니다.입력 딕트를 "정렬"하여 이 문제를 해결할 수 있습니다(다음과 같이 일관된 순서로 키를 사용하여 다시 생성).[{k:d[k] for k in dicts[0].keys()} for d in dicts](이전 버전에서는, 이것은 순효과가 없는 추가 작업이 될 것입니다.)그러나, 이것은 복잡성을 더하며, 이러한 이중 압축 방식은 받아쓰기 이해를 사용하는 이전 방식보다 어떠한 이점도 제공하지 않습니다.

결과를 명시적으로 구축하여 핵심 사항을 즉시 발견

일라이 벤더스키의 대답처럼, 그러나 함수로서:

from collections import defaultdict

def merge(dicts):
    result = defaultdict(list)
    for d in dicts:
        for key, value in d.items():
            result[key].append(value)
    return result

이렇게 하면 다음과 같은 결과를 얻을 수 있습니다.defaultdictdict표준 라이브러리에 의해 정의됩니다.기본 제공 명령어만 사용하는 코드는 다음과 같습니다.

def merge(dicts):
    result = {}
    for d in dicts:
        for key, value in d.items():
            result.setdefault(key, []).append(value)
    return result

목록 외에 다른 컨테이너 유형 사용

사전 키튜플을 데잘입니다; 합니다. 목록 이해를 대체합니다.[d[k] for d in dicts if k in d]와 함께tuple(d[k] for d in dicts if k in d) 생자식다전니다달합으로 합니다.tuple시자공 ("twiple comprehension"은 없습니다.

튜플은 불변이고 그것을 가지고 있지 않기 때문에.append방법, 명시적 루프 접근법은 대체하여 수정되어야 합니다..append(value)와 함께+= (value,)그러나 키 중복이 많은 경우 매번 새 튜플을 만들어야 하므로 성능이 저하될 수 있습니다.목록을 먼저 작성한 다음 최종 결과를 다음과 같은 것으로 변환하는 것이 더 나을 수 있습니다.{k: tuple(v) for (k, v) in merged.items()}.

집합을 얻기 위해 유사한 수정을 할 수 있습니다(설정된 이해력이 있지만, 다음을 사용합니다).{}등), Numpy 열등 배등.를 들어,는 두 방식을 다음과 같은 할 수 .

def merge(dicts, value_type=list):
    # First, figure out which keys are present.
    keys = set().union(*dicts)
    # Build a dict with those keys, using a list comprehension to
    # pull the values from the source dicts.
    return {
        k: value_type(d[k] for d in dicts if k in d)
        for k in keys
    }

그리고.

from collections import defaultdict

def merge(dicts, value_type=list):
    # We stick with hard-coded `list` for the first part,
    # because even other mutable types will offer different interfaces.
    result = defaultdict(list)
    for d in dicts:
        for key, value in d.items():
            result[key].append(value)
    # This is redundant for the default case, of course.
    return {k:value_type(v) for (k, v) in result}

입력 값이 이미 시퀀스인 경우

소스의 값을 새 목록으로 묶는 대신 값이 모두 이미 목록인 입력을 가져와 출력에서 해당 목록을 연결(또는 튜플 또는 1차원 Numpy 배열 연결, 결합 세트 등)하려는 경우가 많습니다.

이것은 여전히 사소한 수정입니다.사전 계산된 키의 경우 플랫 결과를 얻기 위해 순서대로 중첩된 목록 이해를 사용합니다.

def merge(dicts):
    keys = set().union(*dicts)
    return {
        k: [v for d in dicts if k in d for v in d[k]]
        # Alternately:
        # k: [v for d in dicts for v in d.get(k, [])]
        for k in keys
    }

대신 사용할 수 있습니다.sum원래 목록 이해의 결과를 연결합니다.이렇게 하지 마십시오. 중복 키가 많으면 성능이 저하됩니다. 제공되는 트인sum시퀀스에 대해 최적화되지 않았으며("스트링"을 명시적으로 허용하지 않음) 각 추가 항목이 있는 새 목록을 내부적으로 생성하려고 시도합니다.

명적루프접사용경할우을식방을 합니다..extend.append:

from collections import defaultdict

def merge(dicts):
    result = defaultdict(list)
    for d in dicts:
        for key, value in d.items():
            result[key].extend(value)
    return result

extend리스트의 메소드는 임의의 반복 가능한 값을 허용하므로 값에 대한 튜플이 있는 입력에서 작동합니다. 물론 여전히 출력에 목록을 사용합니다. 물론 이러한 입력은 이전에 표시된 대로 다시 변환할 수 있습니다.

입력에 각각 하나의 항목이 있는 경우

이 문제의 일반적인 버전에는 각각 단일 키-값 쌍을 갖는 입력 딕트가 포함됩니다.은 " 또입력다같음수있다니습을과이는다니▁be있"일 수도 있습니다.(key, value)튜플(또는 리스트).

물론 위의 접근법은 여전히 유효합니다. 입력은 튜입 경우의다, 처럼 먼저 .[{k:v} for (k, v) in tuples]를 직접 사용할 수 있습니다.또는 빅토리아 스튜어트의 대답처럼 튜플을 직접 받아들이도록 명시적 반복 접근법을 수정할 수 있습니다.

from collections import defaultdict

def merge(pairs):
    result = defaultdict(list)
    for key, value in pairs:
        result[key].extend(value)
    return result

(키-값 쌍 중 하나만 있고 직접 제공되는 경우 키-값 쌍을 반복할 필요가 없으므로 코드가 단순화되었습니다.)

이러한 에 그나이러단항경키값우별정로을후다렬있다사니습수것는더이용효일과적하를 이 더 일 수 .itertools.groupby이 경우, 튜플을 사용하는 것이 더 쉬워질 것입니다.다음과 같습니다.

from itertools import groupby

def merge(tuples):
    grouped = groupby(tuples, key=lambda t: t[0])
    return {k: [kv[1] for kv in ts] for k, ts in grouped}

여기서,t는 입력의 튜플 중 하나의 이름으로 사용됩니다.grouped값 "키" "키" "키" 합니다.k첫) 및 (반복자)ts그 그룹의 튜플 위에. 쌍에서 합니다.kv에 시대에ts, 을 것들로부목만들고록사다, 그을가용니합로치것의 값으로 하세요.k결과 dict를 키로 입력합니다.

물론 이러한 방식으로 하나의 항목 딕트를 병합하려면 먼저 튜플로 변환해야 합니다.이를 위한 간단한 방법 중 하나는 단일 항목 딕트 목록에 대한 것입니다.[next(iter(d.items())) for d in dicts].

키가 정확히 같은 두 개의 사전이 있다고 가정하면 아래가 가장 간단한 방법입니다(두 솔루션 모두에 대해 python3을 사용해야 함).


d1 = {'a': 1, 'b': 2, 'c':3}
d2 = {'a': 5, 'b': 6, 'c':7} 

# get keys from one of the dictionary
ks = [k for k in d1.keys()]

print(ks)
['a', 'b', 'c']

# call values from each dictionary on available keys
d_merged = {k: (d1[k], d2[k]) for k in ks}

print(d_merged)
{'a': (1, 5), 'b': (2, 6), 'c': (3, 7)}

# to merge values as list
d_merged = {k: [d1[k], d2[k]] for k in ks}
print(d_merged)
{'a': [1, 5], 'b': [2, 6], 'c': [3, 7]}

공통 키가 몇 개 있지만 다른 키가 몇 개 있는 사전이 두 개 있는 경우 모든 키 목록을 준비해야 합니다.


d1 = {'a': 1, 'b': 2, 'c':3, 'd': 9}
d2 = {'a': 5, 'b': 6, 'c':7, 'e': 4} 

# get keys from one of the dictionary
d1_ks = [k for k in d1.keys()]
d2_ks = [k for k in d2.keys()]

all_ks = set(d1_ks + d2_ks)

print(all_ks)
['a', 'b', 'c', 'd', 'e']

# call values from each dictionary on available keys
d_merged = {k: [d1.get(k), d2.get(k)] for k in all_ks}

print(d_merged)
{'d': [9, None], 'a': [1, 5], 'b': [2, 6], 'c': [3, 7], 'e': [None, 4]}

그곳에는 훌륭한 도서관이 있습니다.funcy단 하나의 짧은 줄에서 필요한 일을 하는 것.

from funcy import join_with
from pprint import pprint

d1 = {"key1": "x1", "key2": "y1"}
d2 = {"key1": "x2", "key2": "y2"}

list_of_dicts = [d1, d2]

merged_dict = join_with(tuple, list_of_dicts)

pprint(merged_dict)

출력:

{'key1': ('x1', 'x2'), 'key2': ('y1', 'y2')}

자세한 내용은 funcy -> join_with.

판다가 설치되어 있고 모든 사전의 모든 키가 동일한 경우 한 줄로 수행할 수 있습니다.

import pandas as pd
d1 = {key1: x1, key2: y1}
d2 = {key1: x2, key2: y2}
new_dict = pd.DataFrame([d1,d2]).to_dict('list')
def merge(d1, d2, merge):
    result = dict(d1)
    for k,v in d2.iteritems():
        if k in result:
            result[k] = merge(result[k], v)
        else:
            result[k] = v
    return result

d1 = {'a': 1, 'b': 2}
d2 = {'a': 1, 'b': 3, 'c': 2}
print merge(d1, d2, lambda x, y:(x,y))

{'a': (1, 1), 'c': 2, 'b': (2, 3)}

키가 중첩된 경우:

d1 = { 'key1': { 'nkey1': 'x1' }, 'key2': { 'nkey2': 'y1' } } 
d2 = { 'key1': { 'nkey1': 'x2' }, 'key2': { 'nkey2': 'y2' } }
ds = [d1, d2]
d = {}
for k in d1.keys():
    for k2 in d1[k].keys():
        d.setdefault(k, {})
        d[k].setdefault(k2, [])
        d[k][k2] = tuple(d[k][k2] for d in ds)

산출량:

{'key1': {'nkey1': ('x1', 'x2')}, 'key2': {'nkey2': ('y1', 'y2')}}

목록 사전 대신 튜플 사전(OP가 요청한 내용)을 작성하도록 이 답변 수정:

from collections import defaultdict

d1 = {1: 2, 3: 4}
d2 = {1: 6, 3: 7}

dd = defaultdict(tuple)

for d in (d1, d2): # you can list as many input dicts as you want here
    for key, value in d.items():
        dd[key] += (value,)

print(dd)

위의 내용은 다음과 같습니다.

defaultdict(<class 'tuple'>, {1: (2, 6), 3: (4, 7)})
d1 ={'B': 10, 'C ': 7, 'A': 20}
d2 ={'B': 101, 'Y ': 7, 'X': 8}
d3 ={'A': 201, 'Y ': 77, 'Z': 8}

def CreateNewDictionaryAssemblingAllValues1(d1,d2,d3):
    aa = {
        k :[d[k] for d in (d1,d2,d3) if k in d ] for k in set(d1.keys() | d2.keys() | d3.keys()  )
        }
    aap = print(aa)
    
    return aap

CreateNewDictionaryAssemblingAllValues1(d1, d2, d3)

"""
Output :

{'X': [8], 'C ': [7], 'Y ': [7, 77], 'Z': [8], 'B': [10, 101], 'A': [20, 201]}

"""

blubb 답변:

각 목록의 값을 사용하여 튜플을 직접 구성할 수도 있습니다.

ds = [d1, d2]
d = {}
for k in d1.keys():
  d[k] = (d1[k], d2[k])

튜플에 대한 특정 주문이 있는 경우 유용할 수 있습니다.

ds = [d1, d2, d3, d4]
d = {}
for k in d1.keys():
  d[k] = (d3[k], d1[k], d4[k], d2[k]) #if you wanted tuple in order of d3, d1, d4, d2

아래 방법을 사용하면 키가 동일한 두 사전을 병합할 수 있습니다.

def update_dict(dict1: dict, dict2: dict) -> dict:
output_dict = {}
for key in dict1.keys():
    output_dict.update({key: []})
    if type(dict1[key]) != str:
        for value in dict1[key]:
            output_dict[key].append(value)
    else:
        output_dict[key].append(dict1[key])
    if type(dict2[key]) != str:
        for value in dict2[key]:
            output_dict[key].append(value)
    else:
        output_dict[key].append(dict2[key])

return output_dict

{= { 입력: d1 = {key1: x1, key2: y1} d2 = {key1: x2, key2}
{' ' ' ' {'key1': ['x1', 'x2', 'key2': ['y1', 'y2']}

dicts = [dict1,dict2,dict3]
out   = dict(zip(dicts[0].keys(),[[dic[list(dic.keys())[key]] for dic in dicts] for key in range(0,len(dicts[0]))]))

확실한 가능성.

d1={'a':1,'b':2}
d2={'c':3,'d':4}
context={**d1, **d2}
context
{'b': 2, 'c': 3, 'd': 4, 'a': 1}

언급URL : https://stackoverflow.com/questions/5946236/how-to-merge-dicts-collecting-values-from-matching-keys

반응형