Python: объединение двух словарей с равными ключами с использованием for-loop [duplicate]

В следующем примере, который я написал, показано, как

  • обрабатывать асинхронные HTTP-вызовы;
  • Подождать ответа от каждого вызова API;
  • Использовать шаблон promise ;
  • Используйте шаблон Promise.All для объединения нескольких HTTP-вызовов;

Этот рабочий пример является автономным. Он будет определять простой объект запроса, который использует объект window XMLHttpRequest для совершения вызовов. Он будет определять простую функцию, чтобы дождаться завершения кучи обещаний.

Контекст. В этом примере запрашивается конечная точка Spotify Web API для поиска объектов playlist для заданного набора строк запроса:

[
 "search?type=playlist&q=%22doom%20metal%22",
 "search?type=playlist&q=Adele"
]

Для каждого элемента новый Promise запустит блок - ExecutionBlock, проанализирует результат, заплатит новый набор обещаний на основе массива результатов, который представляет собой список объектов Spotify user и выполняет новый HTTP-вызов в ExecutionProfileBlock асинхронно.

Затем вы можете увидеть вложенную структуру Promise, которая позволяет вам генерировать множественные и полностью асинхронные вложенные HTTP-вызовы и присоединять результаты к каждому подмножеству вызовов через Promise.all.

NOTE Recent Spotify search API-интерфейсам потребуется указать токен доступа в заголовках запроса:

-H "Authorization: Bearer {your access token}" 

Итак, вы должны запустить следующий пример, вам нужно поместить маркер доступа в заголовки запроса:

var spotifyAccessToken = "YourSpotifyAccessToken";
var console = {
    log: function(s) {
        document.getElementById("console").innerHTML += s + "
" } } // Simple XMLHttpRequest // based on https://davidwalsh.name/xmlhttprequest SimpleRequest = { call: function(what, response) { var request; if (window.XMLHttpRequest) { // Mozilla, Safari, ... request = new XMLHttpRequest(); } else if (window.ActiveXObject) { // Internet Explorer try { request = new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) { try { request = new ActiveXObject('Microsoft.XMLHTTP'); } catch (e) {} } } // State changes request.onreadystatechange = function() { if (request.readyState === 4) { // Done if (request.status === 200) { // Complete response(request.responseText) } else response(); } } request.open('GET', what, true); request.setRequestHeader("Authorization", "Bearer " + spotifyAccessToken); request.send(null); } } //PromiseAll var promiseAll = function(items, block, done, fail) { var self = this; var promises = [], index = 0; items.forEach(function(item) { promises.push(function(item, i) { return new Promise(function(resolve, reject) { if (block) { block.apply(this, [item, index, resolve, reject]); } }); }(item, ++index)) }); Promise.all(promises).then(function AcceptHandler(results) { if (done) done(results); }, function ErrorHandler(error) { if (fail) fail(error); }); }; //promiseAll // LP: deferred execution block var ExecutionBlock = function(item, index, resolve, reject) { var url = "https://api.spotify.com/v1/" url += item; console.log( url ) SimpleRequest.call(url, function(result) { if (result) { var profileUrls = JSON.parse(result).playlists.items.map(function(item, index) { return item.owner.href; }) resolve(profileUrls); } else { reject(new Error("call error")); } }) } arr = [ "search?type=playlist&q=%22doom%20metal%22", "search?type=playlist&q=Adele" ] promiseAll(arr, function(item, index, resolve, reject) { console.log("Making request [" + index + "]") ExecutionBlock(item, index, resolve, reject); }, function(results) { // Aggregated results console.log("All profiles received " + results.length); //console.log(JSON.stringify(results[0], null, 2)); ///// promiseall again var ExecutionProfileBlock = function(item, index, resolve, reject) { SimpleRequest.call(item, function(result) { if (result) { var obj = JSON.parse(result); resolve({ name: obj.display_name, followers: obj.followers.total, url: obj.href }); } //result }) } //ExecutionProfileBlock promiseAll(results[0], function(item, index, resolve, reject) { //console.log("Making request [" + index + "] " + item) ExecutionProfileBlock(item, index, resolve, reject); }, function(results) { // aggregated results console.log("All response received " + results.length); console.log(JSON.stringify(results, null, 2)); } , function(error) { // Error console.log(error); }) ///// }, function(error) { // Error console.log(error); });

Я подробно рассмотрел это решение здесь .

1
задан seanscal 19 November 2013 в 15:48
поделиться

6 ответов

Это общая версия. Это может быть использовано для создания словаря со значениями в виде списка, даже если ключ присутствует только в одном из них.

dic1 = {'A': 25, 'B': 41, 'C': 32}
dic2 = {'A': 21, 'B': 12, 'C': 62}
result = {}
for key in (dic1.viewkeys() | dic2.keys()):
    if key in dic1: result.setdefault(key, []).append(dic1[key])
    if key in dic2: result.setdefault(key, []).append(dic2[key])

print result

Выход

{'A': [25, 21], 'C': [32, 62], 'B': [41, 12]}

Если вы используя Python 3, цикл должен быть изменен следующим образом. Благодаря Martijn:)

for key in (dic1.keys() | dic2.keys()):
7
ответ дан thefourtheye 27 August 2018 в 10:07
поделиться
def combineDict(dict1, dict2):
    res = collections.defaultdict(list)
    for key, value in (dict1.items() | dict2.items()):
        res[key].append(value)
    return res

print(combineDict(dict1, dict2))
1
ответ дан Farcaller 27 August 2018 в 10:07
поделиться

Это один из способов, используя defaultdict :

# the setup
>>> from collections import defaultdict
>>> dict1 = {'A': 25, 'B': 41, 'C': 32}
>>> dict2 = {'A': 21, 'B': 12, 'C': 62}

# the preperation
>>> dicts = [dict1, dict2]
>>> final = defaultdict(list)

# the logic
>>> for k, v in ((k, v) for d in dicts for k, v in d.iteritems()):
    final[k].append(v)

# the result
>>> final 
defaultdict(<type 'list'>, {'A': [25, 21], 'C': [32, 62], 'B': [41, 12]})
2
ответ дан Inbar Rose 27 August 2018 в 10:07
поделиться

Как вы знаете, у ваших двух словарей всегда будут одинаковые ключи, вы можете использовать:

finaldict = {key:(dict1[key], dict2[key]) for key in dict1}

, чтобы объединить их, где каждое значение будет кортежем значений из исходных словарей.

6
ответ дан jonrsharpe 27 August 2018 в 10:07
поделиться

Мне просто нужно было объединить словарный номер неизвестного номера и после того, как мы увидели ответы на этот вопрос, появились более универсальные решения:

1) словари значений:

dic1 = {'A': 1, 'B': 1, 'C': 1}
dic2 = {'A': 2, 'B': 2, 'C': 2}
dic3 = {'D': 3, 'E': 3, 'F': 3}

def combineDictVal(*args):
    result = {}
    for dic in args:
        for key in (result.viewkeys() | dic.keys()):
            if key in dic:
                result.setdefault(key, []).append(dic[key])
    return result

print combineDictVal(dic1, dic2, dic3)

Результат : {'A': [1, 2], 'C': [1, 2], 'B': [1, 2], 'E': [3], 'D': [3], 'F': [3]}

2) словари списков (различие находится в append / extend *):

dic1 = {'A': [1, 2], 'B': [1, 2], 'C': [1, 2]}
dic2 = {'A': [3, 4], 'B': [3, 4], 'C': [3, 4]}
dic3 = {'D': [5, 6], 'E': [5, 6], 'F': [5, 6]}

def combineDictList(*args):
    result = {}
    for dic in args:
        for key in (result.viewkeys() | dic.keys()):
            if key in dic:
                result.setdefault(key, []).extend(dic[key])
    return result

print combineDictList(dic1, dic2, dic3)

Результат: {'A': [1, 2, 3, 4], 'C': [1, 2, 3, 4], 'B': [1, 2, 3, 4], 'E': [5, 6], 'D': [5, 6], 'F': [5, 6]}

3) Universal для int / lists:

dic1 = {'A': 1, 'B': 1, 'C': [1, 1]}
dic2 = {'A': 2, 'B': [2, 2], 'C': 2}
dic3 = {'D': 3, 'E': 3, 'F': [3, 3]}

def combineDict(*args):
    result = {}
    for dic in args:
        for key in (result.viewkeys() | dic.keys()):
            if key in dic:
                if type(dic[key]) is list:
                    result.setdefault(key, []).extend(dic[key])
                else:
                    result.setdefault(key, []).append(dic[key])
    return result

print combineDict(dic1, dic2, dic3)

Результат:

{'A': [1, 2], 'C': [1, 1, 2], 'B': [1, 2, 2], 'E': [3], 'D': [3], 'F': [3, 3]}

Эти решения не являются максимально возможными, однако они ясны и работают нормально. Надеюсь, это поможет кому-то.

0
ответ дан mibrl 27 August 2018 в 10:07
поделиться

Это еще один способ сделать это и будет работать независимо от того, присутствуют ли ключи только в одном или в обоих словарях.

def merge_dicts(dict_a, dict_b):
    merged_dict = {key: [value] for key, value in dict_a.iteritems()}
    for key, value in dict_a.iteritems():
        try:
            merged_dict[key].append(value)
        except KeyError:
            meeged_dict[key] = [value]
    return ret_dict
0
ответ дан Steinar Lima 27 August 2018 в 10:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: