Hvordan slå sammen to ordbøker i ett enkelt uttrykk?

stemmer
3k

Jeg har to Python ordbøker, og jeg ønsker å skrive et enkelt uttrykk som returnerer disse to ordbøker, slått sammen. Den update()metoden ville være det jeg trenger, hvis det returneres resultatet i stedet for å modifisere en dict på stedet.

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = x.update(y)
>>> print(z)
None
>>> x
{'a': 1, 'b': 10, 'c': 11}

Hvordan kan jeg få den endelige sammenslåtte dict i z, ikke x?

(For å være ekstra tydelig, den siste-en-vinner konflikt håndtering av dict.update()er det jeg leter etter også.)

Publisert på 02/09/2008 klokken 07:44
kilden bruker
På andre språk...                            


55 svar

stemmer
3k

Hvordan kan jeg slå sammen to Python ordbøker i et enkelt uttrykk?

For ordbøker xog y, zblir en sammenslått ordbok med verdier fra yerstatte de fra x.

  • I Python 3.5 eller høyere,:

    z = {**x, **y}
    w = {'foo': 'bar', 'baz': 'qux', **y}  # merge a dict with literal values
    
  • I Python 2, (eller 3,4 eller lavere) skrive en funksjon:

    def merge_two_dicts(x, y):
        z = x.copy()   # start with x's keys and values
        z.update(y)    # modifies z with y's keys and values & returns None
        return z
    

    og

    z = merge_two_dicts(x, y)
    

Forklaring

Si du har to dicts og du ønsker å sette dem sammen til en ny dict uten å endre de opprinnelige dicts:

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

Ønsket resultat er å få en ny ordbok ( z) med verdiene slått sammen, og den andre dict verdier skrive de fra den første.

>>> z
{'a': 1, 'b': 3, 'c': 4}

En ny syntaks for dette, foreslått i PEP 448 og tilgjengelig fra og Python 3.5 , er

z = {**x, **y}

Og det er faktisk et enkelt uttrykk. Det viser nå som implementert i utgivelsesplan for 3,5, PEP 478 , og det har nå gjort sin vei inn Hva er nytt i Python 3.5 dokumentet.

Men siden mange organisasjoner er fortsatt på Python 2, kan du ønsker å gjøre dette i en bakoverkompatibel måte. Det klassiske Pytonske måte, tilgjengelig i Python 2 og Python 3,0-3,4, er å gjøre dette som en to-trinns prosess:

z = x.copy()
z.update(y) # which returns None since it mutates z

I begge tilnærminger, yvil komme andre og dens verdier vil erstatte x's verdier, og dermed 'b'vil peke på 3i vår endelige resultatet.

Ennå ikke på Python 3.5, men ønsker en enkelt uttrykk

Hvis du ennå ikke er på Python 3.5, eller trenger å skrive bakoverkompatibel kode, og ønsker deg dette i et enkelt uttrykk , den mest performant mens riktige tilnærmingen er å sette den i en funksjon:

def merge_two_dicts(x, y):
    """Given two dicts, merge them into a new dict as a shallow copy."""
    z = x.copy()
    z.update(y)
    return z

og da har du et enkelt uttrykk:

z = merge_two_dicts(x, y)

Du kan også lage en funksjon for å slå sammen en udefinert antall dicts, fra null til et meget stort antall:

def merge_dicts(*dict_args):
    """
    Given any number of dicts, shallow copy and merge into a new dict,
    precedence goes to key value pairs in latter dicts.
    """
    result = {}
    for dictionary in dict_args:
        result.update(dictionary)
    return result

Denne funksjonen vil fungere i Python 2 og 3 for alle dicts. f.eks gitt dicts atil g:

z = merge_dicts(a, b, c, d, e, f, g) 

og sentrale verdi parene i ghar forrang over dicts atil f, og så videre.

Kritikk av andre svar

Ikke bruk det du ser i tidligere aksepterte svaret:

z = dict(x.items() + y.items())

I Python 2, oppretter du to lister i minnet for hver dict, opprette en tredje liste i minnet med lengde lik lengden av de to første satt sammen, og deretter forkaste alle tre listene for å lage dict. I Python 3, vil dette mislykkes fordi du legger to dict_itemsstedene sammen, ikke to lister -

>>> c = dict(a.items() + b.items())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'dict_items' and 'dict_items'

og du må eksplisitt opprette dem som lister, f.eks z = dict(list(x.items()) + list(y.items())). Dette er en sløsing med ressurser og datakraft.

Likeledes tar foreningen av items()i Python 3 ( viewitems()i Python 2,7) også vil svikte når verdiene er unhashable objekter (for eksempel lister, for eksempel). Selv om dine verdier er hashable, siden settene er semantisk uordnet, er atferden udefinert i forhold til prioritet. Så ikke gjør dette:

>>> c = dict(a.items() | b.items())

Dette eksemplet viser hva som skjer når verdiene er unhashable:

>>> x = {'a': []}
>>> y = {'b': []}
>>> dict(x.items() | y.items())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

Her er et eksempel der y skal ha forrang, men i stedet verdien fra x beholdes på grunn av vilkårlig rekkefølge sett:

>>> x = {'a': 2}
>>> y = {'a': 1}
>>> dict(x.items() | y.items())
{'a': 2}

En annen hacke bør du ikke bruke:

z = dict(x, **y)

Dette bruker dictkonstruktøren, og er veldig rask og minne effektiv (enda litt mer-enn våre to-trinns prosess), men med mindre du vet nøyaktig hva som skjer her (det vil si den andre dict er gått som søkeord argumenter til dict konstruktøren), er det vanskelig å lese, det er ikke den tiltenkte bruk, og så er det ikke Pytonske.

Her er et eksempel på bruken blir sanert i Django .

Dicts er ment å ta hashable nøkler (f.eks frozensets eller tupler), men denne metoden mislykkes i Python tre når tastene er ikke strenger.

>>> c = dict(a, **b)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: keyword arguments must be strings

Fra adresseliste , Guido van Rossum, skaperen av språket, skrev:

Jeg er fint med erklære dict ({}, ** {1: 3}) ulovlig, ettersom det er tross alt misbruk av ** mekanismen.

og

Tilsynelatende dict (x, ** y) går rundt som "cool hack" for "call x.update (y) og returnere x". Personlig finner jeg det mer avskyelig enn kjølig.

Det er min forståelse (samt forståelsen av skaperen av språket ) som den tiltenkte bruk for dict(**y)er for å lage dicts for lesbarhet formål, f.eks:

dict(a=1, b=10, c=11)

i stedet for

{'a': 1, 'b': 10, 'c': 11}

Respons på kommentarer

Til tross for hva Guido sier, dict(x, **y)er i tråd med dict spesifikasjonen, som btw. fungerer for både Python 2 og 3. Det faktum at dette fungerer bare for strykere nøkler er en direkte konsekvens av hvordan søkeordet parametere fungerer og ikke en kort-comming av dict. Heller ikke ved bruk av ** operatør på dette sted et misbruk av mekanismen, faktisk ** er designet nettopp å passere dicts som søkeord.

Igjen, det fungerer ikke for tre når nøkler er ikke-strenger. Den implisitte ringer Kontrakten er at navnerom ta vanlige dicts, mens brukerne må bare passere søkeord argumenter som er strenger. Alle andre callables håndheves det. dictbrøt denne konsistens i Python 2:

>>> foo(**{('a', 'b'): None})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() keywords must be strings
>>> dict(**{('a', 'b'): None})
{('a', 'b'): None}

Denne inkonsekvensen ble dårlig gitt andre implementeringer av Python (PYPY, Jython, Ironpython). Således ble det løst i Python 3, da dette bruk kan det allikevel være en brudd forandring.

Jeg sender til deg at det er skadelig inkompetanse for forsettlig skrive kode som fungerer bare i én versjon av et språk eller som bare fungerer gitt visse vilkårlige begrensninger.

En annen kommentar:

dict(x.items() + y.items()) er fortsatt den mest lesbare løsningen for Python 2. Lesbarhet teller.

Mitt svar: merge_two_dicts(x, y)faktisk virker mye klarere for meg, hvis vi er faktisk bekymret for lesbarhet. Og det er ikke videre kompatibelt, som Python 2 er i økende grad foreldet.

Mindre performant men riktig Ad-hocs

Disse metodene er mindre performant, men de vil gi korrekt oppførsel. De vil være mye mindre performant enn copyog updateeller den nye utpakking fordi de iterere gjennom hver nøkkelverdi-paret på et høyere abstraksjonsnivå, men de gjør respekterer den rekkefølge (sistnevnte dicts har forrang)

Du kan også KJEDE dicts manuelt inne i en dict forståelse:

{k: v for d in dicts for k, v in d.items()} # iteritems in Python 2.7

eller i python 2,6 (og kanskje så tidlig som 2,4 når generator uttrykk ble innført):

dict((k, v) for d in dicts for k, v in d.items())

itertools.chain vil KJEDE itera over nøkkelverdi-par i riktig rekkefølge:

import itertools
z = dict(itertools.chain(x.iteritems(), y.iteritems()))

Performance Analysis

Jeg bare kommer til å gjøre ytelsen analyse av bruksområder er kjent for å opptre korrekt.

import timeit

Følgende er gjort på Ubuntu 14.04

I Python 2,7 (system Python):

>>> min(timeit.repeat(lambda: merge_two_dicts(x, y)))
0.5726828575134277
>>> min(timeit.repeat(lambda: {k: v for d in (x, y) for k, v in d.items()} ))
1.163769006729126
>>> min(timeit.repeat(lambda: dict(itertools.chain(x.iteritems(), y.iteritems()))))
1.1614501476287842
>>> min(timeit.repeat(lambda: dict((k, v) for d in (x, y) for k, v in d.items())))
2.2345519065856934

I Python 3.5 (deadsnakes PPA):

>>> min(timeit.repeat(lambda: {**x, **y}))
0.4094954460160807
>>> min(timeit.repeat(lambda: merge_two_dicts(x, y)))
0.7881555100320838
>>> min(timeit.repeat(lambda: {k: v for d in (x, y) for k, v in d.items()} ))
1.4525277839857154
>>> min(timeit.repeat(lambda: dict(itertools.chain(x.items(), y.items()))))
2.3143140770262107
>>> min(timeit.repeat(lambda: dict((k, v) for d in (x, y) for k, v in d.items())))
3.2069112799945287

Ressurser på Dictionaries

Svarte 10/11/2014 kl. 22:11
kilden bruker

stemmer
1k

I ditt tilfelle, hva du kan gjøre er:

z = dict(x.items() + y.items())

Dette vil, slik du vil ha den, sette den endelige dict i z, og gjøre verdien for nøkkelen bbli skikkelig overstyres av andre ( y) dict verdi:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = dict(x.items() + y.items())
>>> z
{'a': 1, 'c': 11, 'b': 10}

Hvis du bruker Python 3, er det bare litt mer komplisert. For å opprette z:

>>> z = dict(list(x.items()) + list(y.items()))
>>> z
{'a': 1, 'c': 11, 'b': 10}
Svarte 02/09/2008 kl. 07:50
kilden bruker

stemmer
550

Et alternativ:

z = x.copy()
z.update(y)
Svarte 02/09/2008 kl. 13:00
kilden bruker

stemmer
274

En annen, mer konsis, alternativ:

z = dict(x, **y)

Merk : Dette har blitt et populært svar, men det er viktig å påpeke at hvis yhar noen ikke-streng nøkler, det faktum at dette fungerer i det hele tatt er et misbruk av en CPython implementering detalj, og det fungerer ikke i Python tre, eller i PYPY, Ironpython, eller Jython. Dessuten er Guido ikke en fan . Så jeg kan ikke anbefale denne teknikken for fremtids kompatibel eller kryss-implementering bærbar kode, som egentlig betyr at det bør unngås helt.

Svarte 02/09/2008 kl. 15:52
kilden bruker

stemmer
168

Dette vil sannsynligvis ikke være et populært svar, men du nesten helt sikkert ikke ønsker å gjøre dette. Hvis du ønsker en kopi som er en sammenslåing, og deretter bruke kopi (eller deepcopy , avhengig av hva du vil), og deretter oppdatere. De to linjer med kode er mye mer lesbare - mer Pytonske - enn én linje med etableringen .items () + (.items). Eksplisitt er bedre enn implisitt.

I tillegg, når du bruker .items () (pre Python 3.0), du oppretter en ny liste som inneholder elementer fra dict. Hvis ordbøker er store, så det er ganske mye overhead (to store lister som vil bli kastet bort så snart det fusjonerte dict er opprettet). oppdatering () kan arbeide mer effektivt, fordi den kan kjøres gjennom den andre dict punkt-for-punkt.

I form av tid :

>>> timeit.Timer("dict(x, **y)", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
15.52571702003479
>>> timeit.Timer("temp = x.copy()\ntemp.update(y)", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
15.694622993469238
>>> timeit.Timer("dict(x.items() + y.items())", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
41.484580039978027

IMO den lille nedgangen mellom de to første er verdt det for lesbarhet. I tillegg ble søkeord argumenter for ordboken etableringen bare lagt i Python 2.3, mens kopier () og oppdatering () vil fungere i eldre versjoner.

Svarte 08/09/2008 kl. 11:16
kilden bruker

stemmer
116

I en oppfølgings svar, spurte deg om den relative ytelsen av disse to alternativene:

z1 = dict(x.items() + y.items())
z2 = dict(x, **y)

På min maskin, i hvert fall (en ganske vanlig x86_64 kjører Python 2.5.2), alternativ z2er ikke bare kortere og enklere, men også betydelig raskere. Du kan kontrollere dette selv ved hjelp av timeitmodulen som følger med Python.

Eksempel 1: identiske ordbøker kartlegging 20 etterfølgende heltall i seg selv:

% python -m timeit -s 'x=y=dict((i,i) for i in range(20))' 'z1=dict(x.items() + y.items())'
100000 loops, best of 3: 5.67 usec per loop
% python -m timeit -s 'x=y=dict((i,i) for i in range(20))' 'z2=dict(x, **y)' 
100000 loops, best of 3: 1.53 usec per loop

z2vinner med en faktor på 3,5 eller så. Ulike ordbøker synes å gi helt andre resultater, men z2alltid synes å komme ut fremover. (Hvis du får inkonsistente resultater for samme test, prøv passerer -rmed en rekke større enn standard 3.)

Eksempel 2: ikke-overlappende ordbøker kartlegging 252 korte strenger til heltall og vice versa:

% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z1=dict(x.items() + y.items())'
1000 loops, best of 3: 260 usec per loop
% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z2=dict(x, **y)'               
10000 loops, best of 3: 26.9 usec per loop

z2 vinner av en faktor på 10. Det er en ganske stor seier i min bok!

Etter sammen disse to, lurte jeg på om z1's dårlig ytelse kunne tilskrives overhead med å konstruere to punkt lister, som igjen førte meg til å lure på om denne variasjonen kan fungere bedre:

from itertools import chain
z3 = dict(chain(x.iteritems(), y.iteritems()))

Et par raske tester, for eksempel

% python -m timeit -s 'from itertools import chain; from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z3=dict(chain(x.iteritems(), y.iteritems()))'
10000 loops, best of 3: 66 usec per loop

føre meg til å konkludere med at z3er noe raskere enn z1, men ikke på langt nær så fort som z2. Definitivt ikke verdt all den ekstra skrive.

Denne diskusjonen er fortsatt mangler noe viktig, noe som er en ytelse sammenligning av disse alternativene med "opplagte" måte å slå sammen to lister: ved hjelp av updatemetoden. For å prøve å holde ting på lik linje med de uttrykkene, ingen som modifiserer x eller y, jeg kommer til å lage en kopi av x i stedet for å endre det på stedet, som følger:

z0 = dict(x)
z0.update(y)

Et typisk resultat:

% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z0=dict(x); z0.update(y)'
10000 loops, best of 3: 26.9 usec per loop

Med andre ord, z0og z2ser ut til å ha i det vesentlige samme ytelse. Tror du dette kan være en tilfeldighet? Jeg gjør ikke....

Faktisk vil jeg gå så langt som å hevde at det er umulig for ren Python-kode for å gjøre noe bedre enn dette. Og hvis du kan gjøre betydelig bedre i en C forlengelse modul, jeg forestille Python folk kan godt være interessert i å innlemme koden din (eller en variant av din tilnærming) i Python kjerne. Python bruker dicti mange steder; optimalisere sin virksomhet er en stor avtale.

Du kan også skrive dette som

z0 = x.copy()
z0.update(y)

som Tony gjør, men (ikke overrask) forskjellen i notasjon viser seg ikke å ha noen målbar virkning på ytelsen. Bruk den ser rett for deg. Selvfølgelig, han er helt riktig å påpeke at de to-setningen versjonen er mye enklere å forstå.

Svarte 23/10/2008 kl. 02:38
kilden bruker

stemmer
85

Jeg ønsket noe lignende, men med mulighet til å spesifisere hvordan verdiene på like nøkler ble slått sammen, så jeg hacket ut dette (men ikke tungt teste den). Selvfølgelig er dette ikke et enkelt uttrykk, men det er en enkelt funksjon samtale.

def merge(d1, d2, merge_fn=lambda x,y:y):
    """
    Merges two dictionaries, non-destructively, combining 
    values on duplicate keys as defined by the optional merge
    function.  The default behavior replaces the values in d1
    with corresponding values in d2.  (There is no other generally
    applicable merge strategy, but often you'll have homogeneous 
    types in your dicts, so specifying a merge technique can be 
    valuable.)

    Examples:

    >>> d1
    {'a': 1, 'c': 3, 'b': 2}
    >>> merge(d1, d1)
    {'a': 1, 'c': 3, 'b': 2}
    >>> merge(d1, d1, lambda x,y: x+y)
    {'a': 2, 'c': 6, 'b': 4}

    """
    result = dict(d1)
    for k,v in d2.iteritems():
        if k in result:
            result[k] = merge_fn(result[k], v)
        else:
            result[k] = v
    return result
Svarte 04/09/2008 kl. 19:08
kilden bruker

stemmer
76

I Python 3, kan du bruke collections.ChainMap hvilke grupper flere dicts eller andre tilordninger sammen for å skape et enkelt, oppdateres visning:

>>> from collections import ChainMap
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = ChainMap({}, y, x)
>>> for k, v in z.items():
        print(k, '-->', v)

a --> 1
b --> 10
c --> 11
Svarte 28/04/2013 kl. 03:15
kilden bruker

stemmer
60

Rekursivt / dyp oppdatere en dict

def deepupdate(original, update):
    """
    Recursively update a dict.
    Subdict's won't be overwritten but also updated.
    """
    for key, value in original.iteritems(): 
        if key not in update:
            update[key] = value
        elif isinstance(value, dict):
            deepupdate(value, update[key]) 
    return update

Demonstrasjon:

pluto_original = {
    'name': 'Pluto',
    'details': {
        'tail': True,
        'color': 'orange'
    }
}

pluto_update = {
    'name': 'Pluutoo',
    'details': {
        'color': 'blue'
    }
}

print deepupdate(pluto_original, pluto_update)

utganger:

{
    'name': 'Pluutoo',
    'details': {
        'color': 'blue',
        'tail': True
    }
}

Takket rednaw for redigeringer.

Svarte 29/11/2011 kl. 11:52
kilden bruker

stemmer
53

Den beste versjonen jeg kunne tenke mens ikke bruke kopier vil være:

from itertools import chain
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
dict(chain(x.iteritems(), y.iteritems()))

Det er raskere enn dict(x.items() + y.items()), men ikke så fort som n = copy(a); n.update(b), i hvert fall på CPython. Denne versjonen fungerer også i Python tre hvis du endrer iteritems()til items(), som automatisk gjort av 2to3 verktøyet.

Personlig liker jeg denne versjonen best fordi det beskriver ganske godt hva jeg ønsker i en enkel funksjonell syntaks. Bare marginale problemet er at det ikke gjør helt klart at verdier fra y går foran verdier fra x, men jeg tror ikke det er vanskelig å finne ut av.

Svarte 14/10/2010 kl. 18:55
kilden bruker

stemmer
41

Python 3.5 (PEP 448) gjør en bedre syntaks alternativ:

x = {'a': 1, 'b': 1}
y = {'a': 2, 'c': 2}
final = {**x, **y} 
final
# {'a': 2, 'b': 1, 'c': 2}

Eller

final = {'a': 1, 'b': 1, **x, **y}
Svarte 26/02/2015 kl. 21:27
kilden bruker

stemmer
39
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = dict(x.items() + y.items())
print z

For elementer med nøklene i begge ordbøker ( 'b'), kan du kontrollere hvilken som ender opp i utgangs ved å sette som en siste.

Svarte 02/09/2008 kl. 07:49
kilden bruker

stemmer
34

Mens spørsmålet allerede er besvart flere ganger, har denne enkle løsningen på problemet ikke vært oppført ennå.

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z4 = {}
z4.update(x)
z4.update(y)

Det er så fort som z0 og de onde z2 er nevnt ovenfor, men lett å forstå og endre.

Svarte 14/10/2011 kl. 16:12
kilden bruker

stemmer
32
def dict_merge(a, b):
  c = a.copy()
  c.update(b)
  return c

new = dict_merge(old, extras)

Blant slike lyssky og tvilsomme svar, dette er lysende eksempel den eneste god måte å fusjonere dicts i Python, støttet av diktatoren for livet Guido van Rossum selv! Noen andre foreslo halvparten av dette, men ikke legg den i en funksjon.

print dict_merge(
      {'color':'red', 'model':'Mini'},
      {'model':'Ferrari', 'owner':'Carl'})

gir:

{'color': 'red', 'owner': 'Carl', 'model': 'Ferrari'}
Svarte 06/08/2012 kl. 09:24
kilden bruker

stemmer
24

Hvis du tror lambdaene er onde da ikke lese videre. Som forespurt, kan du skrive raskt og minneeffektiv løsning med ett uttrykk:

x = {'a':1, 'b':2}
y = {'b':10, 'c':11}
z = (lambda a, b: (lambda a_copy: a_copy.update(b) or a_copy)(a.copy()))(x, y)
print z
{'a': 1, 'c': 11, 'b': 10}
print x
{'a': 1, 'b': 2}

Som antydet ovenfor, ved hjelp av to linjer eller skrive en funksjon er trolig en bedre vei å gå.

Svarte 23/11/2011 kl. 18:08
kilden bruker

stemmer
19

Vær Pytonske. Bruk en forståelse :

z={i:d[i] for d in [x,y] for i in d}

>>> print z
{'a': 1, 'c': 11, 'b': 10}
Svarte 20/01/2016 kl. 11:46
kilden bruker

stemmer
18

I python3, den itemsmetoden ikke lenger returnerer en liste , men snarere en visning , som fungerer som et sett. I dette tilfellet må du ta settet union siden lenke sammen med +vil ikke fungere:

dict(x.items() | y.items())

For python3-lignende oppførsel i versjon 2.7, det viewitemsbør metoden fungerer i stedet for items:

dict(x.viewitems() | y.viewitems())

Jeg foretrekker denne notasjonen anyways siden det virker mer naturlig å tenke på det som et sett union operasjon i stedet for sammensetning (som tittelen viser).

Redigere:

Et par flere poeng for python 3. Først oppmerksom på at dict(x, **y)kunsten ikke vil fungere i python tre mindre nøklene i yer strenger.

Også Raymond Hettinger er Chainmap Svaret er ganske elegant, siden det kan ta et vilkårlig antall dicts som argumenter, men fra docs det ser ut som det sekvensielt ser gjennom en liste over alle dicts for hvert oppslag:

Oppslag søke de underliggende kartlegginger suksessivt inntil en nøkkel er funnet.

Dette kan bremse deg ned hvis du har mange oppslag i søknaden:

In [1]: from collections import ChainMap
In [2]: from string import ascii_uppercase as up, ascii_lowercase as lo; x = dict(zip(lo, up)); y = dict(zip(up, lo))
In [3]: chainmap_dict = ChainMap(y, x)
In [4]: union_dict = dict(x.items() | y.items())
In [5]: timeit for k in union_dict: union_dict[k]
100000 loops, best of 3: 2.15 µs per loop
In [6]: timeit for k in chainmap_dict: chainmap_dict[k]
10000 loops, best of 3: 27.1 µs per loop

Så om en størrelsesorden tregere for oppslag. Jeg er en fan av Chainmap, men ser mindre praktisk der det kan være mange oppslag.

Svarte 09/10/2013 kl. 18:09
kilden bruker

stemmer
13

Enkel løsning med itertools som bevarer orden (sistnevnte dicts har forrang)

import itertools as it
merge = lambda *args: dict(it.chain.from_iterable(it.imap(dict.iteritems, args)))

Og det er bruk:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> merge(x, y)
{'a': 1, 'b': 10, 'c': 11}

>>> z = {'c': 3, 'd': 4}
>>> merge(x, y, z)
{'a': 1, 'b': 10, 'c': 3, 'd': 4}
Svarte 04/08/2015 kl. 14:54
kilden bruker

stemmer
13

Misbruk fører til ett uttrykk løsning for Matthew svar :

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = (lambda f=x.copy(): (f.update(y), f)[1])()
>>> z
{'a': 1, 'c': 11, 'b': 10}

Du sa du ville ett uttrykk, så jeg misbrukt lambdatil å binde et navn, og tupler å overstyre lambda er en utfoldelse grensen. Føl deg fri til å krype.

Du kan også gjøre dette selvfølgelig hvis du ikke bryr deg om å kopiere det:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = (x.update(y), x)[1]
>>> z
{'a': 1, 'b': 10, 'c': 11}
Svarte 07/08/2013 kl. 21:23
kilden bruker

stemmer
11

I python 3:

import collections
a = {1: 1, 2: 2}
b = {2: 3, 3: 4}
c = {3: 5}

r = dict(collections.ChainMap(a, b, c))
print(r)

Ute:

{1: 1, 2: 2, 3: 4}

Dokumenter: https://docs.python.org/3/library/collections.html#collections.ChainMap :

Svarte 24/05/2017 kl. 07:24
kilden bruker

stemmer
11

to ordbøker

def union2(dict1, dict2):
    return dict(list(dict1.items()) + list(dict2.items()))

n ordbøker

def union(*dicts):
    return dict(itertools.chain.from_iterable(dct.items() for dct in dicts))

sumhar dårlig ytelse. se https://mathieularose.com/how-not-to-flatten-a-list-of-lists-in-python/

Svarte 17/10/2012 kl. 02:09
kilden bruker

stemmer
9

Selv om svarene var god for denne grunne ordboken, ingen av metodene som er definert her faktisk gjør et dypt ordbok flette.

Eksempler:

a = { 'one': { 'depth_2': True }, 'two': True }
b = { 'one': { 'extra': False } }
print dict(a.items() + b.items())

En ville forvente et resultat av noe som dette:

{ 'one': { 'extra': False', 'depth_2': True }, 'two': True }

I stedet får vi dette:

{'two': True, 'one': {'extra': False}}

Det 'en' entry skulle ha hatt 'depth_2' og 'ekstra' som elementer i ordboka om det virkelig var en sammenslåing.

Ved hjelp av kjeden også, ikke fungerer:

from itertools import chain
print dict(chain(a.iteritems(), b.iteritems()))

Resulterer i:

{'two': True, 'one': {'extra': False}}

Den dype flette at rcwesick ga også skaper samme resultat.

Ja, det vil fungere å fusjonere eksempel ordbøker, men ingen av dem er en generisk mekanisme for å fusjonere. Jeg vil oppdatere denne senere når jeg skriver en metode som gjør en sann flette.

Svarte 03/08/2012 kl. 23:36
kilden bruker

stemmer
8

For Python 2:

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = dict(x.items()+y.items())
print(z)

For Python 3:

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = dict(x.items()|y.items())
print(z)

Det gir utgang:{'a': 1, 'c': 11, 'b': 10}

Svarte 31/08/2016 kl. 13:53
kilden bruker

stemmer
7

Tegning på ideer her og andre steder jeg har forstått en funksjon:

def merge(*dicts, **kv): 
      return { k:v for d in list(dicts) + [kv] for k,v in d.items() }

Bruk (testet i python 3):

assert (merge({1:11,'a':'aaa'},{1:99, 'b':'bbb'},foo='bar')==\
    {1: 99, 'foo': 'bar', 'b': 'bbb', 'a': 'aaa'})

assert (merge(foo='bar')=={'foo': 'bar'})

assert (merge({1:11},{1:99},foo='bar',baz='quux')==\
    {1: 99, 'foo': 'bar', 'baz':'quux'})

assert (merge({1:11},{1:99})=={1: 99})

Du kan bruke en lambda i stedet.

Svarte 19/07/2013 kl. 05:49
kilden bruker

stemmer
5

Du kan bruke toolz.merge([x, y])for dette.

Svarte 18/11/2016 kl. 12:53
kilden bruker

stemmer
5

I Python 3.5 kan du bruke pakke ut **for å skape nye ordboka. Denne metoden har ikke vært vist i tidligere svar. Dessuten er det bedre å bruke {}i stedet for dict(). Fordi {}er en python bokstavelig og dict()innebærer et funksjonskall.

dict1 = {'a':1}
dict2 = {'b':2}
new_dict = {**dict1, **dict2}
>>>new_dict
{'a':1, 'a':2}
Svarte 28/09/2016 kl. 00:33
kilden bruker

stemmer
5

(For Python2.7 * bare, det er enklere løsninger for Python3 *.)

Hvis du ikke er uvillig til å importere en standard bibliotek modul, kan du gjøre

from functools import reduce

def merge_dicts(*dicts):
    return reduce(lambda a, d: a.update(d) or a, dicts, {})

(The or alitt i lambdaer nødvendig fordi dict.updatealltid tilbake Nonepå suksess.)

Svarte 28/03/2016 kl. 13:13
kilden bruker

stemmer
5
from collections import Counter
dict1 = {'a':1, 'b': 2}
dict2 = {'b':10, 'c': 11}
result = dict(Counter(dict1) + Counter(dict2))

Dette bør løse problemet.

Svarte 30/11/2015 kl. 13:04
kilden bruker

stemmer
5

Dette kan gjøres med et enkelt dict forståelse:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> { key: y[key] if key in y else x[key]
      for key in set(x) + set(y)
    }

Etter mitt syn det beste svaret for 'single uttrykket' del som ingen ekstra funksjoner er nødvendig, og det er kort.

Svarte 17/07/2015 kl. 14:47
kilden bruker

stemmer
5

Problemet jeg har med løsninger oppført hittil er at i det fusjonerte ordboken, verdien for nøkkel "b" er 10, men til min måte å tenke på, bør det være 12. I dette lyset, jeg presentere følgende:

import timeit

n=100000
su = """
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
"""

def timeMerge(f,su,niter):
    print "{:4f} sec for: {:30s}".format(timeit.Timer(f,setup=su).timeit(n),f)

timeMerge("dict(x, **y)",su,n)
timeMerge("x.update(y)",su,n)
timeMerge("dict(x.items() + y.items())",su,n)
timeMerge("for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k] ",su,n)

#confirm for loop adds b entries together
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k]
print "confirm b elements are added:",x

resultater:

0.049465 sec for: dict(x, **y)
0.033729 sec for: x.update(y)                   
0.150380 sec for: dict(x.items() + y.items())   
0.083120 sec for: for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k]

confirm b elements are added: {'a': 1, 'c': 11, 'b': 12}
Svarte 03/12/2013 kl. 18:11
kilden bruker

stemmer
5
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> x, z = dict(x), x.update(y) or x
>>> x
{'a': 1, 'b': 2}
>>> y
{'c': 11, 'b': 10}
>>> z
{'a': 1, 'c': 11, 'b': 10}
Svarte 13/11/2013 kl. 10:01
kilden bruker

stemmer
4

i python2

dict(mydict, **other)

eller

In [11]: dict({1:2}.items() + {2:3}.items() + {1:5}.items() )
Out[11]: {1: 5, 2: 3}

python3

{ **mydict, **otherdict}
Svarte 28/06/2018 kl. 12:33
kilden bruker

stemmer
4

Ved hjelp av en dict forståelse, du kan

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}

dc = {xi:(x[xi] if xi not in list(y.keys()) 
           else y[xi]) for xi in list(x.keys())+(list(y.keys()))}

gir

>>> dc
{'a': 1, 'c': 11, 'b': 10}

Merk syntaksen for if elsei forståelse

{ (some_key if condition else default_key):(something_if_true if condition 
          else something_if_false) for key, value in dict_.items() }
Svarte 27/05/2013 kl. 09:04
kilden bruker

stemmer
3

Hvis du ikke har noe imot å mutere x,

x.update(y) or x

Enkelt, lesbar, performant. Du vet update() alltid tilbake None, som er en falsk verdi. Så det vil alltid vurdere å x.

Mutere metoder i standard bibliotek, som update, retur Noneav konvensjonen, så dette trikset vil fungere på dem også.

Hvis du bruker et bibliotek som ikke følger denne konvensjonen, kan du bruke en tuppel skjerm og indeksere å gjøre det en enkelt uttrykk, i stedet for or, men det er ikke så lesbar.

(x.update(y), x)[-1]

Hvis du ikke har xen variabel ennå, kan du bruke lambdatil å lage en lokal uten å bruke et oppdrag uttalelse. Dette utgjør ved hjelp lambdasom la uttrykk , som er en vanlig teknikk i funksjonelle språk, men heller unpythonic.

(lambda x: x.update(y) or x)({'a':1, 'b': 2})

Hvis du ønsker en kopi, PEP 448 er best {**x, **y}. Men hvis det ikke er tilgjengelig, la fungerer her også.

(lambda z: z.update(y) or z)(x.copy())
Svarte 22/09/2017 kl. 02:57
kilden bruker

stemmer
3

Jeg vet at dette ikke helt passer detaljene i spørsmålene ( "one liner"), men siden ingen av svarene ovenfor gikk inn i denne retning, mens masse, masse svar adressert ytelsesproblemet, følte jeg at jeg bør bidra mine tanker.

Avhengig av bruken tilfelle kan det ikke være nødvendig å lage en "ekte" fusjonerte ordbok av de gitte inngangs ordbøker. En visning som gjør dette kan være tilstrekkelig i mange tilfeller, det vil si et objekt som fungerer som det fusjonerte ordboken ville uten å beregne det helt. En lat versjon av det fusjonerte ordbok, så å si.

I Python, dette er ganske enkel og kan gjøres med koden vist i slutten av innlegget mitt. Denne gitt, ville svaret på det opprinnelige spørsmålet være:

z = MergeDict(x, y)

Når du bruker denne nye objektet, vil den oppføre seg som en sammenslått ordbok, men det vil ha konstant opprettelse tid og konstant minne fotavtrykk og samtidig la de opprinnelige ordbøker urørt. Lage det er måten billigere enn i de andre løsningene som foreslås.

Selvfølgelig, hvis du bruker resultatet mye, så vil du på et tidspunkt når grensen der skape en ekte sammenslåtte ordboken ville ha vært raskere løsning. Som jeg sa, det avhenger av din brukstilfelle.

Hvis du noen gang følt at du foretrekker å ha en reell fusjonert dict, deretter ringer dict(z)ville produsere det (men måten mer kostbart enn de andre løsningene selvfølgelig, så dette er bare verdt å nevne).

Du kan også bruke denne klassen til å lage en slags kopi-on-write ordboken:

a = { 'x': 3, 'y': 4 }
b = MergeDict(a)  # we merge just one dict
b['x'] = 5
print b  # will print {'x': 5, 'y': 4}
print a  # will print {'y': 4, 'x': 3}

Her er rett-frem koden MergeDict:

class MergeDict(object):
  def __init__(self, *originals):
    self.originals = ({},) + originals[::-1]  # reversed

  def __getitem__(self, key):
    for original in self.originals:
      try:
        return original[key]
      except KeyError:
        pass
    raise KeyError(key)

  def __setitem__(self, key, value):
    self.originals[0][key] = value

  def __iter__(self):
    return iter(self.keys())

  def __repr__(self):
    return '%s(%s)' % (
      self.__class__.__name__,
      ', '.join(repr(original)
          for original in reversed(self.originals)))

  def __str__(self):
    return '{%s}' % ', '.join(
        '%r: %r' % i for i in self.iteritems())

  def iteritems(self):
    found = set()
    for original in self.originals:
      for k, v in original.iteritems():
        if k not in found:
          yield k, v
          found.add(k)

  def items(self):
    return list(self.iteritems())

  def keys(self):
    return list(k for k, _ in self.iteritems())

  def values(self):
    return list(v for _, v in self.iteritems())
Svarte 18/05/2016 kl. 15:57
kilden bruker

stemmer
3

Det er så dumt at .updatereturnerer ingenting.
Jeg bare bruke en enkel hjelpefunksjon for å løse problemet:

def merge(dict1,*dicts):
    for dict2 in dicts:
        dict1.update(dict2)
    return dict1

eksempler:

merge(dict1,dict2)
merge(dict1,dict2,dict3)
merge(dict1,dict2,dict3,dict4)
merge({},dict1,dict2)  # this one returns a new copy
Svarte 02/03/2014 kl. 01:44
kilden bruker

stemmer
2
a = {1: 2, 3: 4, 5: 6}
b = {7:8, 1:2}
combined = dict(a.items() + b.items())
print combined
Svarte 21/03/2015 kl. 00:06
kilden bruker

stemmer
1

Det vil være en ny mulighet når Python 3.8 utgivelser ( planlagt til 20 oktober 2019 ), takket være PEP 572: Oppgave uttrykk . Den nye oppdrag uttrykk operatør :=lar deg tilordne resultatet av copyog fortsatt bruke den til å ringe update, slik at den kombinerte kode et enkelt uttrykk, snarere enn to uttalelser, endring:

newdict = dict1.copy()
newdict.update(dict2)

til:

(newdict := dict1.copy()).update(dict2)

mens oppfører identisk på alle måter. Hvis man også må returnere den resulterende dict(du bedt om et uttrykk retur av dict, den ovenfor skaper og tilordner til newdict, men ikke returnere den, slik at man ikke kan bruke den til å passere et argument for en funksjon som er, a la myfunc((newdict := dict1.copy()).update(dict2))) da bare legge or newdicttil enden (siden updatereturnerer None, som er falsy, det vil deretter evaluere og tilbake newdictsom følge av uttrykket):

(newdict := dict1.copy()).update(dict2) or newdict

Viktig påminnelse: Generelt vil jeg fraråde denne tilnærmingen til fordel for:

newdict = {**dict1, **dict2}

Utpakking tilnærmingen er klarere (for alle som vet om generalisert utpakking i første omgang, som du bør ), krever ikke et navn for resultatet i det hele tatt (så det er mye mer konsis når du bygger en midlertidig som umiddelbart sendes til en funksjon eller inkludert i en list/ tuplebokstavelig eller lignende), og er nesten helt sikkert raskere i tillegg blir (på CPython) omtrent tilsvarende:

newdict = {}
newdict.update(dict1)
newdict.update(dict2)

men gjøres på C-lag, ved hjelp av betong dictAPI, slik at ingen dynamisk metode oppslag / binding eller funksjonskallet utsendelse overhead er involvert (der (newdict := dict1.copy()).update(dict2)er uunngåelig identisk med den opprinnelige to liner i oppførsel, utfører arbeidet i diskrete trinn, med dynamisk oppslag / binding / påkalling av metoder.

Det er også mer utvidbar, som sammenslåing tre dicts er åpenbar:

 newdict = {**dict1, **dict2, **dict3}

der du bruker oppgave uttrykk vil ikke skalere sånn; det nærmeste du kan få vil være:

 (newdict := dict1.copy()).update(dict2), newdict.update(dict3)

eller uten den midlertidige tuppelen Nones, men med truthiness testing av hver Noneresultat:

 (newdict := dict1.copy()).update(dict2) or newdict.update(dict3)

idet hver av disse er selvsagt mye styggere, og inkluderer ytterligere ineffektivitet (enten en bortkastet midlertidig tupleav Nones for komma separasjon, eller meningsløs truthiness testing av hver updatesin Noneretur for orseparasjon).

Den eneste virkelige fordelen til oppdraget uttrykk tilnærming oppstår dersom:

  1. Du har generisk kode som må håndtere både sets og dicts (begge støtte copyog updateså koden fungerer omtrent som du forventer det til)
  2. Du forventer å motta vilkår dict-lignende gjenstander , ikke bare dictseg selv, og må bevare type og semantikk på venstre side (i stedet for å ende opp med en vanlig dict). Mens myspecialdict({**speciala, **specialb})kan fungere, ville det innebære en ekstra midlertidig dict, og hvis myspecialdicthar funksjoner og slett dictikke kan bevare (f.eks vanlige dicts nå bevare orden basert på den første visningen av en nøkkel, og verdi basert på siste opptreden på en tast, kan det være lurt en som bevarer orden basert på den siste opptreden på en tast så oppdaterer en verdi flytter den også til slutt), så semantikk ville være galt. Siden oppdraget uttrykk versjonen bruker de navngitte metoder (som er formodentlig overbelastet å oppføre seg riktig), skaper det aldri en dicti det hele tatt (med mindre dict1det allerede en dict), bevare den opprinnelige type (og originaltype er semantikk), alt mens du unngår eventuelle midlertidige.
Svarte 28/02/2019 kl. 17:16
kilden bruker

stemmer
1

En forening av OP to ordbøker ville være noe sånt som:

{'a': 1, 'b': 2, 10, 'c': 11}

Nærmere bestemt foreningen av to enheter ( xog y) inneholder alle elementene i xog / eller y. Dessverre, hva OP spør om er ikke en union, til tross for tittelen på innlegget.

Min koden under verken elegant eller en one-liner, men jeg tror det er i samsvar med betydningen av unionen.

Fra OP 'eksempel:

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}

z = {}
for k, v in x.items():
    if not k in z:
        z[k] = [(v)]
    else:
        z[k].append((v))
for k, v in y.items():
    if not k in z:
        z[k] = [(v)]
    else:
        z[k].append((v))

{'a': [1], 'b': [2, 10], 'c': [11]}

Enten man ønsker lister kan bli endret, men de ovennevnte vil fungere hvis en ordbok inneholder lister (og nestede lister) som verdier i enten ordbok.

Svarte 30/09/2014 kl. 02:36
kilden bruker

stemmer
1

Jeg har en løsning som ikke er spesifisert her (mannen jeg elsker python) :-)

z = {}
z.update(x) or z.update(y)

Dette vil ikke oppdatere x samt y. Opptreden? Jeg tror ikke det vil være fryktelig sakte :-)

MERK: Det er ment å være 'eller' drift og ikke 'og' operasjon. Redigert å rette koden.

Svarte 05/12/2013 kl. 08:02
kilden bruker

stemmer
0
 d1 = {'a': 10, 'b': 20}
 d2 = {'c': 30, 'd': 40, 'b': 50}
 l = d1.copy()
 s.update(d2)
 print(s)

produksjon:

{'a': 10, 'b': 50, 'c': 30, 'd': 4
Svarte 14/09/2019 kl. 19:33
kilden bruker

stemmer
0

Du kan bruke en funksjon for å gjøre det:

def append(d1, d2):
    d1.update(d2)
    return d1

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = append(x, y)
print(z) #{'a': 1, 'b': 10, 'c': 11}
Svarte 19/07/2019 kl. 23:44
kilden bruker

stemmer
0

For Python 3:

from collections import ChainMap
a = {"a": 1, "b":2}
b = {"c":5, "d":8}
dict(ChainMap(a,b))  # {"a":1, "b":2, "c":5, "d":8}

Hvis du har samme nøkkel i begge ordbøkene, vil ChanMap bruke den første nøkkelen verdi og ignorerer andre nøkkel verdi. Jubel!

Svarte 31/05/2019 kl. 20:10
kilden bruker

stemmer
0

en rask løsning vil være:

z4 = x.copy().update(y)
Svarte 26/03/2019 kl. 12:03
kilden bruker

stemmer
0

Jeg vil si at du bør gjøre følgende:

z = dict(x.items() + y.items())
Svarte 19/03/2019 kl. 06:40
kilden bruker

stemmer
0

Jeg tror mine stygge one-liners er bare nødvendig her.

z = next(z.update(y) or z for z in [x.copy()])
# or
z = (lambda z: z.update(y) or z)(x.copy())
  1. Dicts er slått sammen.
  2. Enkelt uttrykk.
  3. Ikke noen gang tør å bruke den.
Svarte 11/05/2018 kl. 10:00
kilden bruker

stemmer
0

Dette er et uttrykk for Python 3,5 eller høyere som fusjonerer ordbøker ved hjelp av reduce:

>>> from functools import reduce
>>> l = [{'a': 1}, {'b': 2}, {'a': 100, 'c': 3}]
>>> reduce(lambda x, y: {**x, **y}, l, {})
{'a': 100, 'b': 2, 'c': 3}

Merk: Dette fungerer selv om ordlisten listen er tom eller inneholder bare ett element.

Svarte 15/04/2018 kl. 23:02
kilden bruker

stemmer
0

Jeg var nysgjerrig på om jeg kunne slå den aksepterte svaret tid med en linje stringify tilnærming:

Jeg prøvde 5 metoder, ingen tidligere nevnt - alt en rutebåt - alle produserende riktige svarer - og jeg kunne ikke komme i nærheten.

Så ... for å spare deg bryet og kanskje oppfylle nysgjerrighet:

import json
import yaml
import time
from ast import literal_eval as literal

def merge_two_dicts(x, y):
    z = x.copy()   # start with x's keys and values
    z.update(y)    # modifies z with y's keys and values & returns None
    return z

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}

start = time.time()
for i in range(10000):
    z = yaml.load((str(x)+str(y)).replace('}{',', '))
elapsed = (time.time()-start)
print (elapsed, z, 'stringify yaml')

start = time.time()
for i in range(10000):
    z = literal((str(x)+str(y)).replace('}{',', '))
elapsed = (time.time()-start)
print (elapsed, z, 'stringify literal')

start = time.time()
for i in range(10000):
    z = eval((str(x)+str(y)).replace('}{',', '))
elapsed = (time.time()-start)
print (elapsed, z, 'stringify eval')

start = time.time()
for i in range(10000):
    z = {k:int(v) for k,v in (dict(zip(
            ((str(x)+str(y))
            .replace('}',' ')
            .replace('{',' ')
            .replace(':',' ')
            .replace(',',' ')
            .replace("'",'')
            .strip()
            .split('  '))[::2], 
            ((str(x)+str(y))
            .replace('}',' ')
            .replace('{',' ').replace(':',' ')
            .replace(',',' ')
            .replace("'",'')
            .strip()
            .split('  '))[1::2]
             ))).items()}
elapsed = (time.time()-start)
print (elapsed, z, 'stringify replace')

start = time.time()
for i in range(10000):
    z = json.loads(str((str(x)+str(y)).replace('}{',', ').replace("'",'"')))
elapsed = (time.time()-start)
print (elapsed, z, 'stringify json')

start = time.time()
for i in range(10000):
    z = merge_two_dicts(x, y)
elapsed = (time.time()-start)
print (elapsed, z, 'accepted')

resultater:

7.693928956985474 {'c': 11, 'b': 10, 'a': 1} stringify yaml
0.29134678840637207 {'c': 11, 'b': 10, 'a': 1} stringify literal
0.2208399772644043 {'c': 11, 'b': 10, 'a': 1} stringify eval
0.1106564998626709 {'c': 11, 'b': 10, 'a': 1} stringify replace
0.07989692687988281 {'c': 11, 'b': 10, 'a': 1} stringify json
0.005082368850708008 {'c': 11, 'b': 10, 'a': 1} accepted

hva jeg gjorde lære av dette er at jsontilnærmingen er den raskeste måten (av de som forsøkte) å returnere en ordbok fra streng-of-ordbok; mye raskere (ca 1 / 4th av tiden) av hva jeg anses for å være en vanlig metode å bruke ast. Jeg lærte også at den yamltilnærmingen bør unngås for enhver pris.

Ja, får jeg at dette ikke er den beste / riktige måten så vennligst ikke downvote til negativ glemsel, null er helt fint. Jeg var nysgjerrig på om det var raskere, noe det ikke er, Jeg postet for å bevise det slik.

Svarte 22/03/2018 kl. 04:08
kilden bruker

stemmer
0

kodebiten - siste

python 3.6. *

d1 = {"a":1,"b":2,"c":3}
d2 = {"d":4,"e":5,"f":6}
d3 = {"g":7,"h":8,"j":9}
d4 = {'wtf':'yes'}

d1a = {"a":1,"b":2,"c":3}
d1b = {"a":2,"b":3,"c":4}
d1c = {"a":3,"b":4,"c":5}
d1d = {"a":"wtf"}

def dics_combine(*dics):
    dic_out = {}
    for d in dics:
        if isinstance(d, dict):
            dic_out = {**dic_out, **d}
        else:
            pass
    return dic_out

inp = (d1,d2,d3,d4)
combined_dics = dics_combine(*inp)
print('\n')
print('IN-ORDER: {0}'.format(inp))
print('OUT: {0}'.format(combined_dics))

inp = (d1a,d1b,d1c,d1d)
combined_dics = dics_combine(*inp)
print('\n')
print('IN-ORDER: {0}'.format(inp))
print('OUT: {0}'.format(combined_dics))

inp = (d1d,d1c,d1b,d1a)
combined_dics = dics_combine(*inp)
print('\n')
print('IN-ORDER: {0}'.format(inp))
print('OUT: {0}'.format(combined_dics)))

Sett i rekkefølge: ({ 'en': 1, 'b': 2, 'c': 3}, { 'd': 4, 'e': 5, 'f': 6}, { 'g': 7, 'h': 8, 'j': 9}, { 'wtf': 'ja'})

OUT: { 'en': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5, 'f': 6, 'g': 7, 'h': 8 , 'j': 9, 'wtf': 'ja'}

Sett i rekkefølge: ({ 'en': 1, 'b': 2, 'c': 3}, { 'en': 2, 'b': 3, 'c': 4}, { 'en': 3, 'b': 4, 'c': 5}, { 'en': 'wtf'})

OUT: { 'en': 'wtf', 'f': 4, 'c': 5}

Sett i rekkefølge: ({ 'en': 'wtf'}, { 'en': 3, 'b': 4, 'c': 5}, { 'en': 2, 'b': 3, 'c ': 4}, {' en ': 1, 'b': 2, 'c': 3})

OUT: { 'en': 1, 'b': 2, 'c': 3}

Svarte 07/02/2018 kl. 22:05
kilden bruker

stemmer
0

Spørsmålet er merket python-3x, men tar hensyn til at det er en ganske fersk og at det mest var, aksepterte svar for mye med en Python 2.x løsning, jeg tør legge en liner som trekker på en irriterende funksjon i Python 2.x liste forståelse, er at navn lekker ...

$ python2
Python 2.7.13 (default, Jan 19 2017, 14:48:08) 
[GCC 6.3.0 20170118] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> [z.update(d) for z in [{}] for d in (x, y)]
[None, None]
>>> z
{'a': 1, 'c': 11, 'b': 10}
>>> ...

Jeg er glad for å si at det ikke fungerer lenger på noen versjon av Python tre.

Svarte 30/05/2017 kl. 12:28
kilden bruker

stemmer
0

**skaper en mellommann dict, noe som betyr at det totale antall eksemplarer er faktisk høyere gjør dict(one, **two)form, men alt som skjer i C, så det er fortsatt generelt raskere enn å gå til itertools, med mindre det finnes et stort antall kopier (eller, sannsynligvis, hvis kopiene er veldig dyrt). Som alltid hvis du faktisk bryr deg om hastighet bør du tiden din brukstilfelle.

Timing på Python 2.7.3 med en tom dict:

$ python -m timeit "dict({}, **{})"
1000000 loops, best of 3: 0.405 usec per loop

$ python -m timeit -s "from itertools import chain" \
    "dict(chain({}.iteritems(), {}.iteritems()))"
1000000 loops, best of 3: 1.18 usec per loop

Med 10.000 (liten) elementer:

$ python -m timeit -s 'd = {i: str(i) for i in xrange(10000)}' \
    "dict(d, **d)"
1000 loops, best of 3: 550 usec per loop

$ python -m timeit -s "from itertools import chain" -s 'd = {i: str(i) for i in xrange(10000)}' \
    "dict(chain(d.iteritems(), d.iteritems()))"
1000 loops, best of 3: 1.11 msec per loop

Med 100.000 poster:

$ python -m timeit -s 'd = {i: str(i) for i in xrange(100000)}' \
    "dict(d, **d)"
10 loops, best of 3: 19.6 msec per loop

$ python -m timeit -s "from itertools import chain" -s 'd = {i: str(i) for i in xrange(100000)}' \
    "dict(chain(d.iteritems(), d.iteritems()))"
10 loops, best of 3: 20.1 msec per loop

Med 1.000.000 elementer:

$ python -m timeit -s 'd = {i: str(i) for i in xrange(1000000)}' \
    "dict(d, **d)"
10 loops, best of 3: 273 msec per loop

$ python -m timeit -s "from itertools import chain" -s 'd = {i: str(i) for i in xrange(1000000)}' \
    "dict(chain(d.iteritems(), d.iteritems()))"
10 loops, best of 3: 233 msec per loop
Svarte 06/09/2013 kl. 20:18
kilden bruker

stemmer
-1

Hvor er problemet i koden din?

I Python, er ordboken defineres som en uordnet samling av nøkkel-verdi sammenkoblede elementer der tastene er unike og uforanderlige objekter.

Den update()metoden oppdaterer ringer ordboken objekt dvs. xmed innholdet passerer ordbok objekt dvs y.

Hvis den finner noen duplisert nøkkel i kall objekt så vil det overstyre sin verdi med verdien som tilsvarer den matchet nøkkelen til bestått objekt.

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}

Så får du {'a': 1, 'b': 10, 'c': 11}i stedet for å få{'a': 1, 'b': 10, 'c': 11, 'b': 2}

Bruke ordbok forståelse til å løse

Den profesjonelle måten å lage ordbøker som bruker eksisterende ordbøker eller andre iteratorknapper stedene.

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>>
>>> my_dicts = (x, y);  # Gathering all dictionaries in a tuple/list
>>> z = {key: value for my_dict in my_dicts for key, value in my_dict.iteritems()}; # Single line of code that creates new dictionary object from existing dictionaries
>>> z
{'a': 1, 'c': 11, 'b': 10}

referanser

https://www.datacamp.com/community/tutorials/python-dictionary-comprehension

Takk.

Svarte 07/05/2018 kl. 06:53
kilden bruker

stemmer
-3

x = { "a": 1}

y = { "b": 2}

x.update (y)

print x # { 'en': 1, 'b': 2}

Svarte 20/11/2017 kl. 11:53
kilden bruker

stemmer
-4

Her er noen kode, virker det til å fungere ok:

def merge(d1, d2, mode=0):
    if not type(d2) is dict:
        raise Exception("d2 is not a dict")

    if not type(d1) is dict:
        if mode == 0:
            raise Exception("d1 is not a dict")
        return d2

    result = dict(d1)

    for k, v in d2.iteritems():
        if k in result and type(v) is dict:
            result[k] = merge(result[k], v, 1)
        else:
            if mode == 1:
                result.update(d2)
            else:
                result[k] = v
    return result
Svarte 11/07/2013 kl. 07:13
kilden bruker

stemmer
-5
dictionaries = [{'body': 'text'},
{'correctAnswer': 'text'},
{'ans': 'text'},
{'ans': 'text'}]

final_dictionary = {}
for dictionary in dictionaries:
    for key in dictionary:
        final_dictionary[key] = dictionary[key]

print(final_dictionary)

Det høres ut som du er veldig nytt for Python, så løsningen jeg foreslår er en ovenfor som jeg tror er mest lesbare til noen som bare vet om for-løkker, og gjentar seg nøklene til en ordbok. Den pseudo-koden er som følger:

for each of the dictionaries in the list: 
    add each of the key-value pairs in that dictionary to our final dictionary.
Svarte 04/12/2017 kl. 22:56
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more