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 ways to do it more smartly.
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']}}
CodePudding user response:
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.
CodePudding user response:
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"])
- Using the
dict.setdefault
method does nothing tofinal_result
if it already has the keyroom_key
; otherwise it inserts it with the value of that new dictionary. - We can use the
min
function instead of explicitly comparing values. - And we use the fact that a
set
always has unique values, so we can just call itsadd
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'}}}