Python nested dictionary iterate and create new dictionary

Question:

I have a python dictionary where I am iterating it and creating a new dictionary with some calculations. My current code is working fine but I want to know what are the other different ways to do it?

The logic is-

1. if the same `room` has multiple `rate` codes then append it to that room.
2. get the lowest price for every room type.

Existing Code:

datas = [
    {"code": "A1KXDY", "room": "A1K", "rate": "XDX", "price": 10},
    {"code": "B1KXDY", "room": "B1K", "rate": "XDX", "price": 20},
    {"code": "C1KXDY", "room": "C1K", "rate": "XDX", "price": 30},
    {"code": "A1KXDY", "room": "A1K", "rate": "XDY", "price": 5},
    {"code": "B1KXDY", "room": "B1K", "rate": "XDY", "price": 10},
    {"code": "C1KXDY", "room": "C1K", "rate": "XDY", "price": 40},
]
final_result = {}
for data in datas:
    display_rate = data["price"]
    if data["room"] in final_result:
        existing_room = final_result[data["room"]]
        existing_room["rate_codes"].append(data["rate"])
        current_rate = existing_room["display_rate"]
        if current_rate > display_rate:
            existing_room["display_rate"] = display_rate
        continue

    room_data = {"display_rate": display_rate, "rate_codes": [data["rate"]]}

    final_result[data["room"]] = room_data
print(final_result)

Expected Output:

{'A1K': {'display_rate': 5, 'rate_codes': ['XDX', 'XDY']}, 'B1K': {'display_rate': 10, 'rate_codes': ['XDX', 'XDY']}, 'C1K': {'display_rate': 30, 'rate_codes': ['XDX', 'XDY']}}
Asked By: Always Sunny

||

Answers:

You can use pandas for this.

import pandas as pd

datas = [...]
df = pd.DataFrame(datas)
df = df.groupby('room', as_index=False).agg({'price': min, 'rate': list})
df.rename(columns={'price': 'display_rate', 'rate': 'rate_codes'}, inplace=True)
result = df.to_dict('records')

Output:

[{'room': 'A1K', 'display_rate': 5, 'rate_codes': ['XDX', 'XDY']},
 {'room': 'B1K', 'display_rate': 10, 'rate_codes': ['XDX', 'XDY']},
 {'room': 'C1K', 'display_rate': 30, 'rate_codes': ['XDX', 'XDY']}]

The output can further be treated to match the output you want for final_result.

Answered By: Firelord

I would say your solution is fine. What constitutes "more smartly" is subjective to a large extent anyway.

I suppose, if you were willing to accept a set of rate_codes in the final result instead of a list, you could get away with fairly few lines of code:

final_result = {}
for data in datas:
    room_key = data["room"]  # just for readability
    final_result.setdefault(room_key, {
        "display_rate": data["price"],
        "rate_codes": {data["rate"]}
    })
    final_result[room_key]["display_rate"] = min(
        final_result[room_key]["display_rate"],
        data["price"]
    )
    final_result[room_key]["rate_codes"].add(data["rate"])
  1. Using the dict.setdefault method does nothing to final_result if it already has the key room_key; otherwise it inserts it with the value of that new dictionary.
  2. We can use the min function instead of explicitly comparing values.
  3. And we use the fact that a set always has unique values, so we can just call its add method without needing to check if that rate code already exists.

The result:

{'A1K': {'display_rate': 5, 'rate_codes': {'XDX', 'XDY'}}, 'B1K': {'display_rate': 10, 'rate_codes': {'XDX', 'XDY'}}, 'C1K': {'display_rate': 30, 'rate_codes': {'XDX', 'XDY'}}}
Answered By: Daniil Fajnberg
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.