У меня есть несколько пар слова / ключ-значение, например:
d1 = {key1: x1, key2: y1}
d2 = {key1: x2, key2: y2}
Я хочу, чтобы результат был новым (если возможно, наиболее эффективным способом):
d = {key1: (x1, x2), key2: (y1, y2)}
Собственно, я хочу, чтобы результат d был:
d = {key1: (x1.x1attrib, x2.x2attrib), key2: (y1.y1attrib, y2.y2attrib)}
Если кто-то покажет мне, как получить первый результат, я смогу разобраться с остальным.
python
dictionary
merge
Салил
источник
источник
Ответы:
предполагая, что все ключи всегда присутствуют во всех dicts:
ds = [d1, d2] d = {} for k in d1.iterkeys(): d[k] = tuple(d[k] for d in ds)
Примечание. В Python 3.x используйте следующий код:
ds = [d1, d2] d = {} for k in d1.keys(): d[k] = tuple(d[k] for d in ds)
и если dic содержит массивы numpy:
ds = [d1, d2] d = {} for k in d1.keys(): d[k] = np.concatenate(list(d[k] for d in ds))
источник
d1
будет некорректным (могут отсутствовать ключи в других словах).Вот общее решение, которое будет обрабатывать произвольное количество словарей, в случаях, когда ключи есть только в некоторых из словарей:
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)
Показывает:
defaultdict(<type 'list'>, {1: [2, 6], 3: [4, 7]})
Кроме того, чтобы получить свой
.attrib
, просто изменитеappend(value)
наappend(value.attrib)
источник
tuple
нетlist
.dict
из этого,defaultdict
чтобы у вас было нормальноеdict
поведение для несуществующих ключей и т. Д .:dd = dict(dd)
Если у вас есть только d1 и d2,
from collections import defaultdict d = defaultdict(list) for a, b in d1.items() + d2.items(): d[a].append(b)
источник
Вот один из подходов, который можно использовать, даже если оба словаря не имеют одинаковых ключей:
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
Это сгенерирует следующие данные:
{'a': ['test', 'cool'], 'c': ['clear'], 'b': ['btest', 'main'], 'd': ['dreg']}
источник
set(d1.keys() + d2.keys())
лиset(list(d1.keys()) + list(d2.keys()))
в ответе изменить на (для Python 3.x)? В противном случае будетTypeError: unsupported operand type(s) for +: 'dict_keys' and 'dict_keys'
выдана ошибка в python3.xdict1 = {'m': 2, 'n': 4} dict2 = {'n': 3, 'm': 1}
Убедитесь, что ключи находятся в одинаковом порядке:
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))
дает:
{'m': (2, 1), 'n': (4, 3)}
источник
values()
не определен, поэтому вы можете объединять значения из несвязанных ключей.sorted(d.items())
илиsorted(d.keys())
добиться предсказуемых результатов.Эта функция объединяет два словаря, даже если ключи в двух словарях разные:
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
Пример:
d1 = { 'a': 1, 'b': 2, } d2` = { 'b': 'boat', 'c': 'car', } combine_dict(d1, d2) # Returns: { # 'a': (1,), # 'b': (2, 'boat'), # 'c': ('car',) # }
источник
Обновление Python 3.x
От Эли Бендерски ответ:
Python 3 удалил dict.iteritems, вместо этого используйте dict.items. См. Вики 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)
источник
Предположим, что у вас есть список ВСЕХ ключей (вы можете получить этот список, перебирая все словари и получая их ключи). Назовем это
listKeys
. Также:listValues
это список ВСЕХ значений для одного ключа, которые вы хотите объединить.allDicts
: все словари, которые вы хотите объединить.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
источник
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)}
источник
В дополнение к решениям с двумя списками, вот решение для обработки одного списка.
Пример списка (связанный с NetworkX; отформатирован вручную для удобства чтения):
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'), ...]
Обратите внимание на повторяющиеся значения для тех же краев (определяемых кортежами). Чтобы сопоставить эти «значения» с соответствующими «ключами»:
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']), ...]
При необходимости преобразуйте этот список в 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'], ...}
Рекомендации
источник
От blubb ответ:
Вы также можете напрямую сформировать кортеж, используя значения из каждого списка
ds = [d1, d2] d = {} for k in d1.keys(): d[k] = (d1[k], d2[k])
Это может быть полезно, если у вас есть определенный порядок для ваших кортежей.
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
источник
Эта библиотека мне помогла, у меня был список вложенных ключей с тем же именем, но с разными значениями, каждое другое решение продолжало переопределять эти вложенные ключи.
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)
источник
Если ключи вложены:
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)
дает:
{'key1': {'nkey1': ('x1', 'x2')}, 'key2': {'nkey2': ('y1', 'y2')}}
источник
Компактная возможность
d1={'a':1,'b':2} d2={'c':3,'d':4} context={**d1, **d2} context {'b': 2, 'c': 3, 'd': 4, 'a': 1}
источник