Tengo varios dicts / pares clave-valor como este:
d1 = {key1: x1, key2: y1}
d2 = {key1: x2, key2: y2}
Quiero que el resultado sea un nuevo dictado (de la manera más eficiente, si es posible):
d = {key1: (x1, x2), key2: (y1, y2)}
En realidad, quiero que el resultado d sea:
d = {key1: (x1.x1attrib, x2.x2attrib), key2: (y1.y1attrib, y2.y2attrib)}
Si alguien me muestra cómo obtener el primer resultado, puedo averiguar el resto.
python
dictionary
merge
Salil
fuente
fuente
Respuestas:
asumiendo que todas las claves están siempre presentes en todos los dictados:
ds = [d1, d2] d = {} for k in d1.iterkeys(): d[k] = tuple(d[k] for d in ds)
Nota: En Python 3.x use el siguiente código:
ds = [d1, d2] d = {} for k in d1.keys(): d[k] = tuple(d[k] for d in ds)
y si el dic contiene matrices numpy:
ds = [d1, d2] d = {} for k in d1.keys(): d[k] = np.concatenate(list(d[k] for d in ds))
fuente
d1
no es correcta (puede perder claves en otros dictados).Aquí hay una solución general que manejará una cantidad arbitraria de diccionarios, con casos en los que las claves están solo en algunos de los diccionarios:
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)
Muestra:
defaultdict(<type 'list'>, {1: [2, 6], 3: [4, 7]})
Además, para obtener su
.attrib
, simplemente cambieappend(value)
aappend(value.attrib)
fuente
tuple
nolist
.dict
fuera de ladefaultdict
por lo que tiene normal dedict
comportamiento para las llaves inexistentes, etc:dd = dict(dd)
Si solo tiene d1 y d2,
from collections import defaultdict d = defaultdict(list) for a, b in d1.items() + d2.items(): d[a].append(b)
fuente
dict1 = {'m': 2, 'n': 4} dict2 = {'n': 3, 'm': 1}
Asegurándose de que las claves estén en el mismo orden:
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))
da:
{'m': (2, 1), 'n': (4, 3)}
fuente
values()
no está definido, por lo que es posible que esté fusionando valores de claves no relacionadas.sorted(d.items())
osorted(d.keys())
lograr resultados predecibles.Aquí hay un enfoque que puede usar y que funcionaría incluso si ambos dictonarios no tienen las mismas claves:
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
Esto generaría la siguiente entrada:
{'a': ['test', 'cool'], 'c': ['clear'], 'b': ['btest', 'main'], 'd': ['dreg']}
fuente
set(d1.keys() + d2.keys())
puede cambiar aset(list(d1.keys()) + list(d2.keys()))
en la respuesta (para Python 3.x)? De lo contrario, arrojará unTypeError: unsupported operand type(s) for +: 'dict_keys' and 'dict_keys'
error, en python3.xActualización de Python 3.x
De la respuesta de Eli Bendersky:
Python 3 eliminado dict.iteritems usa dict.items en su lugar. Consulte la wiki de 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)
fuente
Este método fusiona dos dictados incluso si las claves de los dos diccionarios son diferentes:
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
Ejemplo:
d1 = { 'a': 1, 'b': 2, } d2` = { 'b': 'boat', 'c': 'car', } combine_dict(d1, d2) # Returns: { # 'a': (1,), # 'b': (2, 'boat'), # 'c': ('car',) # }
fuente
Suponga que tiene la lista de TODAS las claves (puede obtener esta lista iterando a través de todos los diccionarios y obtener sus claves). Vamos a nombrarlo
listKeys
. También:listValues
es la lista de TODOS los valores de una única clave que desea fusionar.allDicts
: todos los diccionarios que desea fusionar.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
fuente
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)}
fuente
Para complementar las soluciones de dos listas, aquí hay una solución para procesar una sola lista.
Una lista de muestra (relacionada con NetworkX; formateada manualmente aquí para facilitar la lectura):
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'), ...]
Tenga en cuenta los valores duplicados para los mismos bordes (definidos por las tuplas). Para cotejar esos "valores" con sus "claves" correspondientes:
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']), ...]
Si es necesario, convierta esa lista en 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'], ...}
Referencias
fuente
De blubb respuesta:
También puede formar directamente la tupla usando valores de cada lista
ds = [d1, d2] d = {} for k in d1.keys(): d[k] = (d1[k], d2[k])
Esto podría ser útil si tuvieras un orden específico para tus tuplas.
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
fuente
Esta biblioteca me ayudó, tenía una lista de claves anidadas con el mismo nombre pero con diferentes valores, todas las demás soluciones seguían anulando esas claves anidadas.
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)
fuente
Si las claves están anidadas:
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)
rinde:
{'key1': {'nkey1': ('x1', 'x2')}, 'key2': {'nkey2': ('y1', 'y2')}}
fuente
Una posibilidad compacta
d1={'a':1,'b':2} d2={'c':3,'d':4} context={**d1, **d2} context {'b': 2, 'c': 3, 'd': 4, 'a': 1}
fuente