Cum se îmbină mai multe dicte cu aceeași cheie sau cu chei diferite? (Programare, Python, Python 3.X, Dicționar, Îmbină)

Salil a intrebat.

Am mai multe perechi de dicte/cheie-valoare ca aceasta:

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

Vreau ca rezultatul să fie un nou dict (în modul cel mai eficient, dacă este posibil):

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

De fapt, vreau ca rezultatul d să fie:

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

Dacă cineva îmi arată cum să obțin primul rezultat, îmi pot da seama de restul.

Comentarii

  • @Salil: Putem să presupunem că fiecare cheie este prezentă în toate dicționarele? –  > Por Björn Pollex.
  • posibilă duplicare a fuzionării dicționarelor Python –  > Por Johnsyweb.
  • Bună Space_C0wb0y, da, cheile sunt prezente în toate dicționarele. –  > Por Salil.
  • Este absolut crucial să specificați dacă toate dicționarele au aceleași chei. –  > Por yugr.
15 răspunsuri
blubb

presupunând că toate cheile sunt întotdeauna prezente în toate dict-urile:

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

Notă: În Python 3.x folosiți codul de mai jos:

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

și dacă dictele conțin matrici numpy:

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

Comentarii

  • Doar „for k in d1” ar fi de ajuns, cred eu. –  > Por Salil.
  • și d.get(k, None) în loc de d[k] –  > Por tahir.
  • @tahir Acest lucru ar însemna că dictele au chei care nu se potrivesc, astfel încât iterarea peste d1 nu este corectă (s-ar putea să nu se găsească chei în alte dicte). –  > Por yugr.
  • Pentru utilizatorii python 3: d1.iterkeys() =d1.items() –  > Por Riley.
  • Tot nu funcționează pentru mine în Python3.x. Am încercat acest lucru chiar dacă valorile mele nu sunt array-uri și funcționează. Cu toate acestea, valorile de ieșire vor fi array-uri. stackoverflow.com/questions/54040858/… – –  > Por Ric S.
Eli Bendersky

Iată o soluție generală care va gestiona o cantitate arbitrară de dicționare, cu cazuri în care cheile se află doar în unele dintre dicționare:

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)

Arată:

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

De asemenea, pentru a obține .attrib, , trebuie doar să schimbați append(value) în append(value.attrib)

Comentarii

  • Cred că OP dorește ca valorile să fie tuple nu list. –  > Por user225312.
  • @A A: contează cu adevărat? tuples va fi mai dificil de construit în cazul mai general al dicturilor cu intrări multiple în care unele chei nu sunt prezente peste tot, imho –  > Por Eli Bendersky.
  • Este posibil să doriți apoi să faceți un normal dict din defaultdict astfel încât să aveți o normală dict un comportament normal pentru chei inexistente etc: dd = dict(dd) –  > Por Ned Deily.
  • @Ned: bună observație, dar depinde de utilizarea finală a datelor –  > Por Eli Bendersky.
  • @Eli: Nu, nu contează, dar încercam să mă bazez pe ceea ce dorea OP și speram că va exista o soluție pentru tuple de la tine 🙂 –  > Por user225312.
riza

Dacă ai doar d1 și d2,

from collections import defaultdict

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

sateesh

Iată o abordare pe care o poți folosi și care ar funcționa chiar dacă ambele dicționare nu au aceleași chei:

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

Aceasta ar genera intrarea de mai jos:

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

Comentarii

  • Poate set(d1.keys() + d2.keys()) poate fi schimbat în set(list(d1.keys()) + list(d2.keys())) în răspuns (pentru Python 3.x)? În caz contrar, se va arunca un TypeError: unsupported operand type(s) for +: 'dict_keys' and 'dict_keys' eroare, în python3.x –  > Por R4444.
Mahdi Ghelichi
dict1 = {'m': 2, 'n': 4}
dict2 = {'n': 3, 'm': 1}

Asigurați-vă că cheile sunt în aceeași ordine:

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

dă:

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

Comentarii

  • Ordinea elementelor în values() este nedefinită, astfel încât este posibil să fuzionați valori din chei care nu au legătură între ele. –  > Por yugr.
  • Tocmai am aplicat modificările, astfel încât acum poate capta feedback-ul tău –  > Por Mahdi Ghelichi.
  • Nu cred că modificarea va rezolva problema. Trebuie să utilizați sorted(d.items()) sau sorted(d.keys()) pentru a obține rezultate previzibile. –  > Por yugr.
  • Puteți da un exemplu care să dovedească contrariul? dict2_sorted este un dicționar sortat în python ! –  > Por Mahdi Ghelichi.
  • Am făcut o mică cercetare în acest sens. În versiunile recente ale Python (3.6+) ordinea de iterație a început să se potrivească cu ordinea de inserție (vezi de ex. aici), ceea ce face ca codul dvs. să treacă. Dar acest lucru este considerat a fi un detaliu de implementare pe care nu ar trebui să se bazeze. Cel de-al doilea exemplu al meu (a se vedea aici) eșuează în mod fiabil în onlinegdb care utilizează vechiul Python 3.4. Alte interpretoare online folosesc Python-uri mai noi, deci problema nu poate fi reprodusă acolo. –  > Por yugr.
Flux

Această funcție fuzionează două dicționare chiar dacă cheile din cele două dicționare sunt diferite:

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

Exemplu:

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

candid

Actualizare Python 3.x

Din răspunsul lui Eli Bendersky:

Python 3 a eliminat dict.iteritems utilizați dict.items în schimb. Consultați wiki Python: 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)

Lung

Să presupunem că aveți lista cu TOATE cheile (puteți obține această listă prin iterarea prin toate dicționarele și obținerea cheilor lor). Să o numim listKeys. De asemenea, se va numi

  • listValues este lista cu TOATE valorile pentru o singură cheie pe care doriți să o unificați.
  • allDicts: toate dicționarele pe care doriți să le unificați.
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

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

Victoria Stuart

Pentru a completa soluțiile cu două liste, iată o soluție pentru procesarea unui fișier unică listă.

O listă de probă (legată de NetworkX; formatată manual aici pentru a fi mai ușor de citit):

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

print('
ec_num_list:
{}'.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'),
  ...] 

Observați valorile duplicate pentru aceleași muchii (definite de tuple). Pentru a colaționa aceste „valori” cu „cheile” lor corespunzătoare:

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

print('
ec_num_collection:
{}'.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']),
...] 

Dacă este necesar, convertiți această listă în dict:

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

print('
ec_num_collection_dict:
{}'.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'],
  ...}

Referințe

frozen5032

Din răspunsul lui blubb:

Puteți, de asemenea, să formați direct tuple-ul folosind valorile din fiecare listă

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

Acest lucru ar putea fi util dacă ați avea o ordine specifică pentru tuplurile dvs.

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

jmcgrath207

Această bibliotecă m-a ajutat, aveam o listă dict de chei imbricate cu același nume, dar cu valori diferite, orice altă soluție continua să suprascrie acele chei imbricate.

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)

lys

Dacă cheile sunt imbricate:

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)

yields:

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

Presupunând că există două dicționare cu exact aceleași chei, mai jos este cel mai succint mod de a face acest lucru (ar trebui să se utilizeze python3 pentru ambele soluții).


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]}

În cazul în care există două dicționare cu câteva chei comune, dar câteva chei diferite, trebuie pregătită o listă cu toate cheile.


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]}

utilizator2897775

O posibilitate compactă

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

Comentarii

  • întrebarea se referă la fuzionarea dicționarelor cu aceeași cheie. răspunsul dvs. nu este cel cerut. –  > Por Pbd.