동일한 키로 여러 사전을 병합하는 방법은 무엇입니까?


88

다음과 같은 여러 사전 / 키-값 쌍이 있습니다.

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

결과가 새로운 사전이되기를 원합니다 (가능한 경우 가장 효율적인 방법으로).

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

실제로 결과 d는 다음과 같습니다.

d = {key1: (x1.x1attrib, x2.x2attrib), key2: (y1.y1attrib, y2.y2attrib)}  

누군가가 첫 번째 결과를 얻는 방법을 보여 주면 나머지를 알아낼 수 있습니다.


4
@Salil : 모든 사전에 각 키가 있다고 가정 할 수 있습니까?
Björn Pollex


안녕하세요 Space_C0wb0y, 예, 키는 모든 사전에 있습니다.
Salil

모든 dict에 동일한 키가 있는지 여부를 지정하는 것이 절대적으로 중요합니다.
yugr

답변:


46

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

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

3
그냥 "for k in d1"이라고 생각합니다.
Salil

및 d.get (k, None) 대신 d [k]
tahir

1
@tahir 이것은 dict에 일치하지 않는 키가 있으므로 반복 d1이 정확하지 않음을 의미합니다 (다른 dict의 키를 놓칠 수 있음).
yugr

1
파이썬 3 사용자의 경우 : d1.iterkeys () = d1.items ()
Riley

Python3.x에서는 여전히 작동하지 않습니다. 내 값이 배열이 아니더라도 이것을 시도했으며 작동합니다. 그러나 값 출력은 배열입니다. stackoverflow.com/questions/54040858/…
Ric S

74

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

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)

쇼 :

defaultdict(<type 'list'>, {1: [2, 6], 3: [4, 7]})

또한을 얻으려면 다음 .attrib으로 변경하십시오 append(value).append(value.attrib)


나는 영업 이익은 같은 값을 원하는 생각 tuple하지 list.
user225312

1
@AA : 정말 중요한가요? 튜플은 일부 키가 어디에나 존재하지 않는 여러 입력 딕셔너리의보다 일반적인 경우에 구축하기가 더 까다로울 것입니다. imho
Eli Bendersky

1
그런 다음 정상 있도록 할 수 dict의 아웃 defaultdict정상적인 그래서 dict존재하지 않는 키의 동작을 등 : dd = dict(dd)
네드 Deily

@Ned : 좋은 지적이지만 데이터의 최종 사용에 따라 달라집니다
Eli Bendersky

@Eli : 아니요, 중요하지 않습니다.하지만 OP가 원하는 것을 기반으로하고 있었고, 튜플에 대한 해결책이 있기를 바라고있었습니다. :-)
user225312

4

d1과 d2 만 있으면

from collections import defaultdict

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

4

다음은 두 용어가 동일한 키를 가지고 있지 않아도 작동하는 한 가지 접근 방식입니다.

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

d = {}

for key in set(d1.keys() + 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']}

대답에서 set(d1.keys() + d2.keys()) 로 변경할 수 있습니까 set(list(d1.keys()) + list(d2.keys()))(Python 3.x의 경우)? 그렇지 않으면 TypeError: unsupported operand type(s) for +: 'dict_keys' and 'dict_keys'오류가 발생합니다. python3.x
R4444

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

2
의 요소 순서 values()가 정의되지 않았으므로 관련없는 키의 값을 병합 할 수 있습니다.
yugr

방금 변경 사항을 적용하여 이제 피드백을 캡처 할 수 있습니다.
Mahdi

변경 사항이 문제를 해결할 것이라고 생각하지 않습니다. 예측 가능한 결과 를 사용 sorted(d.items())하거나 sorted(d.keys())달성 해야합니다 .
yugr

그렇지 않다는 것을 증명하는 예를들 수 있습니까? dict2_sorted는 파이썬으로 정렬 된 사전입니다!
Mahdi Ghelichi

1
나는 이것에 대해 작은 연구를했다. 최신 버전의 Python (3.6+)에서 반복 순서가 삽입 순서 (예 : 여기 참조)와 일치하기 시작 하여 코드가 통과되었습니다. 그러나 이것은 의존해서는 안되는 구현 세부 사항으로 간주됩니다. 두 번째 예제 ( 여기 참조 ) 는 이전 Python 3.4를 사용하는 onlinegdb 에서 안정적으로 실패합니다 . 다른 온라인 인터프리터는 최신 Python을 사용하므로 문제를 재현 할 수 없습니다.
yugr

2

이 함수는 두 사전의 키가 다른 경우에도 두 사전을 병합합니다.

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

예:

d1 = {
    'a': 1,
    'b': 2,
}
d2` = {
    'b': 'boat',
    'c': 'car',
}
combine_dict(d1, d2)
# Returns: {
#    'a': (1,),
#    'b': (2, 'boat'),
#    'c': ('car',)
# }

1

Python 3.x 업데이트

Eli Bendersky 답변에서 :

Python 3에서 제거 된 dict.iteritems는 대신 dict.items를 사용합니다. Python wiki 참조 : https://wiki.python.org/moin/Python3.0

from collections import defaultdict

dd = defaultdict(list)

for d in (d1, d2):
    for key, value in d.items():
        dd[key].append(value)

1

모든 키 목록이 있다고 가정합니다 (모든 사전을 반복하고 해당 키를 가져 와서이 목록을 가져올 수 있음). 이름을 지정하겠습니다 listKeys. 또한:

  • listValues 병합하려는 단일 키에 대한 모든 값 목록입니다.
  • allDicts: 병합하려는 모든 사전.
result = {}
for k in listKeys:
    listValues = [] #we will convert it to tuple later, if you want.
    for d in allDicts:
       try:
            fileList.append(d[k]) #try to append more values to a single key
        except:
            pass
    if listValues: #if it is not empty
        result[k] = typle(listValues) #convert to tuple, add to new dictionary with key k

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

0

두 가지 목록 솔루션을 보완하기 위해 단일 목록 을 처리하는 솔루션이 있습니다.

샘플 목록 (NetworkX 관련, 가독성을 위해 여기에 수동 형식 지정) :

ec_num_list = [((src, tgt), ec_num['ec_num']) for src, tgt, ec_num in G.edges(data=True)]

print('\nec_num_list:\n{}'.format(ec_num_list))
ec_num_list:
[((82, 433), '1.1.1.1'),
  ((82, 433), '1.1.1.2'),
  ((22, 182), '1.1.1.27'),
  ((22, 3785), '1.2.4.1'),
  ((22, 36), '6.4.1.1'),
  ((145, 36), '1.1.1.37'),
  ((36, 154), '2.3.3.1'),
  ((36, 154), '2.3.3.8'),
  ((36, 72), '4.1.1.32'),
  ...] 

동일한 모서리 (튜플에 의해 정의 됨)에 대한 중복 값을 확인합니다. 해당 "값"을 해당 "키"에 대조하려면 :

from collections import defaultdict
ec_num_collection = defaultdict(list)
for k, v in ec_num_list:
    ec_num_collection[k].append(v)

print('\nec_num_collection:\n{}'.format(ec_num_collection.items()))
ec_num_collection:
[((82, 433), ['1.1.1.1', '1.1.1.2']),   ## << grouped "values"
((22, 182), ['1.1.1.27']),
((22, 3785), ['1.2.4.1']),
((22, 36), ['6.4.1.1']),
((145, 36), ['1.1.1.37']),
((36, 154), ['2.3.3.1', '2.3.3.8']),    ## << grouped "values"
((36, 72), ['4.1.1.32']),
...] 

필요한 경우 해당 목록을 dict로 변환하십시오.

ec_num_collection_dict = {k:v for k, v in zip(ec_num_collection, ec_num_collection)}

print('\nec_num_collection_dict:\n{}'.format(dict(ec_num_collection)))
  ec_num_collection_dict:
  {(82, 433): ['1.1.1.1', '1.1.1.2'],
  (22, 182): ['1.1.1.27'],
  (22, 3785): ['1.2.4.1'],
  (22, 36): ['6.4.1.1'],
  (145, 36): ['1.1.1.37'],
  (36, 154): ['2.3.3.1', '2.3.3.8'],
  (36, 72): ['4.1.1.32'],
  ...}

참고 문헌


0

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

0

이 라이브러리는 저를 도왔습니다. 이름은 같지만 값이 다른 중첩 키의 사전 목록이 있었고 다른 모든 솔루션은 중첩 키를 계속 재정의했습니다.

https://pypi.org/project/deepmerge/

from deepmerge import always_merger

def process_parms(args):
    temp_list = []
    for x in args:
        with open(x, 'r') as stream:
            temp_list.append(yaml.safe_load(stream))

    return always_merger.merge(*temp_list)

0

키가 중첩 된 경우 :

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

-4

컴팩트 한 가능성

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

문제는 동일한 키로 사전을 병합하는 것입니다. 당신은 필수 대답이 아닙니다.
Pbd
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.