Home > Software design >  Combining dictionaries that contain a list of objects in Python
Combining dictionaries that contain a list of objects in Python

Time:03-14

I'm trying to combine two dictionaries (actually JSON). Essentially, the API I'm using only give the three newest values, so I want to combine those with the data I already have to create a longer history.

Here is what I tried:

old = {
    "price_history": [
    {
        "date": "3/13",
        "best_buy_price": 0,
        "best_sell_price": 742
    },
    {
        "date": "3/12",
        "best_buy_price": 0,
        "best_sell_price": 463
    },
    {
        "date": "3/11",
        "best_buy_price": 0,
        "best_sell_price": 445
    },
]}

new = {
    "price_history": [
    {
        "date": "3/14",
        "best_buy_price": 0,
        "best_sell_price": 1000
    },
    {
        "date": "3/13",
        "best_buy_price": 0,
        "best_sell_price": 742
    },
    {
        "date": "3/12",
        "best_buy_price": 0,
        "best_sell_price": 463
    },
]}

price_history = {**old, **new}

However, the output of this ends up being:

    {
        "date": "3/14",
        "best_buy_price": 0,
        "best_sell_price": 1000
    },
    {
        "date": "3/13",
        "best_buy_price": 0,
        "best_sell_price": 742
    },
    {
        "date": "3/12",
        "best_buy_price": 0,
        "best_sell_price": 463
    },

I'm trying to get something like this:

    {
        "date": "3/14",
        "best_buy_price": 0,
        "best_sell_price": 1000
    },
    {
        "date": "3/13",
        "best_buy_price": 0,
        "best_sell_price": 742
    },
    {
        "date": "3/12",
        "best_buy_price": 0,
        "best_sell_price": 463
    },
    {
        "date": "3/11",
        "best_buy_price": 0,
        "best_sell_price": 445
    },

CodePudding user response:

You can try something like this:

from datetime import datetime
def extract(v):
    return (v["date"], v["best_buy_price"], v["best_sell_price"])
temp = sorted(set(extract(v) for v in new["price_history"]) | set(extract(v) for v in old["price_history"]), key=lambda x: datetime.strptime(x[0], "%m/%d"), reverse=True)
price_history = {"price_history": [{"date": v[0], "best_buy_price": v[1], "best_sell_price": v[2]} for v in temp]}

More generally (i.e. more than just 3 keys in the object), you can do something like this (assuming new["price_history"] is non-empty)):

from datetime import datetime
keys = sorted(new["price_history"][0])
date_index = keys.index("date")
def extract(val):
    return tuple(val[k] for k in keys)
temp = sorted(set(extract(v) for v in new["price_history"]) | set(extract(v) for v in old["price_history"]), key=lambda x: datetime.strptime(x[date_index], "%m/%d"), reverse=True)
price_history = {"price_history": [{keys[i]: v[i] for i in range(len(keys))} for v in temp]}

CodePudding user response:

We could filter the data in new until the last entry date in old and prepend it to the list in old:

last_date = old['price_history'][0]['date']
newest_data = [d for d in new['price_history'] if d['date'] > last_date]
old['price_history'] = newest_data   old['price_history']

Then if we print old, it now looks like:

{'price_history': [
    {'date': '3/14', 'best_buy_price': 0, 'best_sell_price': 1000},
    {'date': '3/13', 'best_buy_price': 0, 'best_sell_price': 742},
    {'date': '3/12', 'best_buy_price': 0, 'best_sell_price': 463},
    {'date': '3/11', 'best_buy_price': 0, 'best_sell_price': 445}]}

If your list is large, maybe it's more efficient to use collections.deque for the same job:

from collections import deque
old['price_history'] = deque(old['price_history'])
old['price_history'].extendleft(reversed(newest_data))
  • Related