Wie füge ich mehrere Diktate mit demselben Schlüssel zusammen?

83

Ich habe mehrere Diktate / Schlüssel-Wert-Paare wie folgt:

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

Ich möchte, dass das Ergebnis ein neues Diktat ist (wenn möglich auf die effizienteste Weise):

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

Eigentlich möchte ich, dass Ergebnis d ist:

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

Wenn mir jemand zeigt, wie ich zum ersten Ergebnis komme, kann ich den Rest herausfinden.

Salil
quelle
3
@Salil: Können wir davon ausgehen, dass jeder Schlüssel in allen Wörterbüchern vorhanden ist?
Björn Pollex
Mögliches Duplikat der Zusammenführung von Python-Wörterbüchern
Johnsyweb
Hallo Space_C0wb0y, ja, die Schlüssel sind in allen Wörterbüchern vorhanden.
Salil
Es ist absolut wichtig anzugeben, ob alle Diktate die gleichen Schlüssel haben.
yugr

Antworten:

44

vorausgesetzt, alle Schlüssel sind in allen Diktaten immer vorhanden:

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

Hinweis: Verwenden Sie in Python 3.x den folgenden Code:

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

und wenn das dic numpy arrays enthält:

ds = [d1, d2]
d = {}
for k in d1.keys():
  d[k] = np.concatenate(list(d[k] for d in ds))
blubb
quelle
3
Nur "für k in d1" würde ich denken.
Salil
und d.get (k, None) anstelle von d [k]
tahir
1
@tahir Dies würde bedeuten, dass Diktate nicht übereinstimmende Schlüssel haben, sodass das Durchlaufen d1nicht korrekt ist (möglicherweise fehlen Schlüssel in anderen Diktaten).
yugr
1
Für Python 3-Benutzer: d1.iterkeys () = d1.items ()
Riley
In Python3.x funktioniert es immer noch nicht. Ich habe dies versucht, auch wenn meine Werte keine Arrays sind, und es funktioniert. Die ausgegebenen Werte sind jedoch Arrays. stackoverflow.com/questions/54040858/…
Ric S
73

Hier ist eine allgemeine Lösung, die eine beliebige Anzahl von Wörterbüchern verarbeitet, mit Fällen, in denen Schlüssel nur in einigen Wörterbüchern enthalten sind:

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)

Zeigt an:

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

Um Ihre zu bekommen .attrib, wechseln Sie einfach append(value)zuappend(value.attrib)

Eli Bendersky
quelle
Ich denke, das OP will die Werte als tuplenicht list.
user225312
1
@AA: Ist das wirklich wichtig? Tupel werden im allgemeineren Fall von Mehrfacheingabediktaten schwieriger zu erstellen sein, bei denen einige Schlüssel nicht überall vorhanden sind, imho
Eli Bendersky
1
Vielleicht möchten Sie dann eine Normalität dictdaraus machen , defaultdictdamit Sie ein normales dictVerhalten für nicht vorhandene Schlüssel usw. haben: dd = dict(dd)
Ned Deily
@Ned: guter Punkt, aber es hängt von der eventuellen Verwendung der Daten ab
Eli Bendersky
@ Eli: Nein, es spielt keine Rolle, aber ich habe nur versucht, es auf das zu stützen, was das OP wollte und hoffte, dass es eine Lösung für Tupel von Ihnen geben würde :-)
user225312
4

Wenn Sie nur d1 und d2 haben,

from collections import defaultdict

d = defaultdict(list)
for a, b in d1.items() + d2.items():
    d[a].append(b)
Riza
quelle
4
dict1 = {'m': 2, 'n': 4}
dict2 = {'n': 3, 'm': 1}

Stellen Sie sicher, dass die Schlüssel in derselben Reihenfolge sind:

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

gibt:

{'m': (2, 1), 'n': (4, 3)}
Mahdi Ghelichi
quelle
1
Die Reihenfolge der Elemente in values()ist undefiniert, sodass Sie möglicherweise Werte von nicht verwandten Schlüsseln zusammenführen.
yugr
Ich habe gerade die Änderungen angewendet, damit es jetzt Ihr Feedback erfassen kann
Mahdi Ghelichi
Ich denke nicht, dass die Änderung das Problem beheben wird. Sie müssen vorhersehbare Ergebnisse verwenden sorted(d.items())oder sorted(d.keys())erzielen.
yugr
Können Sie ein Beispiel geben, das das Gegenteil beweist? dict2_sorted ist ein sortiertes Wörterbuch in Python!
Mahdi Ghelichi
Die Tatsache, dass es zufällig für kleine Wörterbücher auf Ihrem Computer funktioniert, ist kein Beweis. Überprüfen Sie hier die Reproduktion .
yugr
3

Hier ist ein Ansatz, den Sie verwenden können, der auch dann funktioniert, wenn beide Diktaturen nicht dieselben Schlüssel haben:

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

Dies würde folgende Eingabe erzeugen:

{'a': ['test', 'cool'], 'c': ['clear'], 'b': ['btest', 'main'], 'd': ['dreg']}
Sateesh
quelle
Kann in der Antwort set(d1.keys() + d2.keys()) geändert werden set(list(d1.keys()) + list(d2.keys()))(für Python 3.x)? Andernfalls wird ein TypeError: unsupported operand type(s) for +: 'dict_keys' and 'dict_keys'Fehler in python3.x
R4444
1

Python 3.x Update

Von Eli Bendersky Antwort:

Python 3 entfernte dict.iteritems verwenden stattdessen dict.items. Siehe 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)
offen
quelle
1

Diese Methode führt zwei Wörter zusammen, auch wenn die Schlüssel in den beiden Wörterbüchern unterschiedlich sind:

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

Beispiel:

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

Angenommen, Sie haben die Liste ALLER Schlüssel (Sie können diese Liste erhalten, indem Sie alle Wörterbücher durchlaufen und deren Schlüssel abrufen). Nennen wir es listKeys. Ebenfalls:

  • listValues ist die Liste ALLER Werte für einen einzelnen Schlüssel, den Sie zusammenführen möchten.
  • allDicts: Alle Wörterbücher, die Sie zusammenführen möchten.
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
Lange
quelle
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)}
ralphtheninja
quelle
0

Als Ergänzung zu den Lösungen mit zwei Listen finden Sie hier eine Lösung zum Verarbeiten einer einzelnen Liste.

Eine Beispielliste (NetworkX-bezogen; hier zur besseren Lesbarkeit manuell formatiert):

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'),
  ...] 

Beachten Sie die doppelten Werte für dieselben Kanten (definiert durch die Tupel). So sortieren Sie diese "Werte" mit den entsprechenden "Schlüsseln":

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']),
...] 

Konvertieren Sie diese Liste bei Bedarf in dikt:

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'],
  ...}

Verweise

Victoria Stuart
quelle
0

Von blubb Antwort:

Sie können das Tupel auch direkt mit Werten aus jeder Liste bilden

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

Dies kann nützlich sein, wenn Sie eine bestimmte Bestellung für Ihre Tupel hatten

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
gefroren5032
quelle
0

Diese Bibliothek hat mir geholfen. Ich hatte eine Diktatliste verschachtelter Schlüssel mit demselben Namen, aber unterschiedlichen Werten. Jede andere Lösung überschrieb diese verschachtelten Schlüssel.

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)
jmcgrath207
quelle
0

Wenn Schlüssel verschachtelt sind:

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)

Ausbeuten:

{'key1': {'nkey1': ('x1', 'x2')}, 'key2': {'nkey2': ('y1', 'y2')}}
lys
quelle
-4

Eine kompakte Möglichkeit

d1={'a':1,'b':2}
d2={'c':3,'d':4}
context={**d1, **d2}
context
{'b': 2, 'c': 3, 'd': 4, 'a': 1}
user2897775
quelle
Die Frage ist, ob Diktate mit demselben Schlüssel zusammengeführt werden. Ihr ist nicht die erforderliche Antwort.
Pbd