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.


3
@Salil: Können wir davon ausgehen, dass jeder Schlüssel in allen Wörterbüchern vorhanden ist?
Björn Pollex


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

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)


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)

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

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

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)

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

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

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

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


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

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)

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

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

Die Frage ist, ob Diktate mit demselben Schlüssel zusammengeführt werden. Ihr ist nicht die erforderliche Antwort.
Pbd
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.