Reputation:
I am trying to write a function that takes in two dicts and returns a merged dict which containing all keys from both dicts and, if any keys exist in both dicts, comparing prices
to keep the lowest value.
x = "{'45': 450, '43': 500, '44.5': 420, '39': 415, '47': 320, '46': 520, '44': 400, '47.5': 480, '40.5': 407, '42.5': 407, '42': 401, '38': 401, '45.5': 435, '37.5': 415, '41': 506, '38.5': 787, '36': 399, '36.5': 410, '48.5': 380, '40': 406, '48': 287, '49.5': 567, '50.5': 850, '51.5': 399, '49': 386}"
y = "{'36': 345.0, '36.5': 360.0, '37.5': 355.0, '38': 375.0, '38.5': 375.0, '39': 370.0, '40': 380.0, '40.5': 395.0, '41': 345.0, '42': 300.0, '42.5': 230.0, '43': 220.0, '44': 220.0, '44.5': 220.0, '45': 220.0, '45.5': 290.0, '46': 225.0, '47': 300.0, '47.5': 265.0, '48': 425.0, '48.5': 275.0, '49': 2000.0, '49.5': 1350.0, '51.5': 2000.0}"
I wrote this function to do it, but I believe it can be written in a more pythonic way
import ast
def compare_prices(dict1,dict2):
temp1 = ast.literal_eval(dict1)
temp2 = ast.literal_eval(dict2)
for k,v in temp1.items():
if k in temp2.keys():
price = temp2[k] if temp2[k] else False
if price:
if v> price:
temp1[k] = price
else:
temp1[k] = v
else:
temp1[k] = v
else:
temp1[k] = v
for k,v in temp2.items():
if k not in temp1.keys():
try:
temp1[k] = v if v else ''
except TypeError:
temp1[k] = v
return dict(sorted(temp1.items()))
Upvotes: 1
Views: 542
Reputation: 1215
You can use **kwargs
to merge the Dictionaries because it expands the contents in a dictionary as a collection of key-value pairs. And we can do the comparison to the keys
that have multiple value
s in the resultant dictionary,
import ast
def compare_prices(dict1, dict2):
temp1 = ast.literal_eval(dict1)
temp2 = ast.literal_eval(dict2)
tempDict = {**temp1, **temp2} # two or more Dicts merged using **kwargs
for key, value in tempDict.items():
if key in temp1 and key in temp2:
tempDict[key] = min([value, temp1[key]]) # sets the minimum value
return tempDict
Output,
print(compare_prices(x, y))
#{'45': 220.0, '43': 220.0, '44.5': 220.0, '39': 370.0, '47': 300.0, '46': 225.0, '44': 220.0, '47.5': 265.0, '40.5': 395.0, '42.5': 230.0, '42': 300.0, '38': 375.0, '45.5': 290.0, '37.5': 355.0, '41': 345.0, '38.5': 375.0, '36': 345.0, '36.5': 360.0, '48.5': 275.0, '40': 380.0, '48': 287, '49.5': 567, '50.5': 850, '51.5': 399, '49': 386}
If you want a sorted dictionary you can use OrderedDict
from collections
library
import ast
from collections import OrderedDict
def compare_prices(dict1, dict2):
temp1 = ast.literal_eval(dict1)
temp2 = ast.literal_eval(dict2)
tempDict = {**temp1, **temp2} # two or more Dicts merged using **kwargs
for key, value in tempDict.items():
if key in temp1 and key in temp2:
tempDict[key] = min([value, temp1[key]]) # sets the minimum value
return OrderedDict(sorted(tempDict.items(), key=lambda t: t[0]))
Output,
print(compare_prices(x, y))
#OrderedDict([('36', 345.0), ('36.5', 360.0), ('37.5', 355.0), ('38', 375.0), ('38.5', 375.0), ('39', 370.0), ('40', 380.0), ('40.5', 395.0), ('41', 345.0), ('42', 300.0), ('42.5', 230.0), ('43', 220.0), ('44', 220.0), ('44.5', 220.0), ('45', 220.0), ('45.5', 290.0), ('46', 225.0), ('47', 300.0), ('47.5', 265.0), ('48', 287), ('48.5', 275.0), ('49', 386), ('49.5', 567), ('50.5', 850), ('51.5', 399)])
Upvotes: 0
Reputation: 42133
You could do it with a dictionary comprehension by merging the two dictionary with the minimum value of common keys:
{ **x, **y, **{k:min(x[k],y[k]) for k in x if k in y} }
output:
{'45': 220.0, '43': 220.0, '44.5': 220.0, '39': 370.0, '47': 300.0, '46': 225.0, '44': 220.0, '47.5': 265.0, '40.5': 395.0, '42.5': 230.0, '42': 300.0, '38': 375.0, '45.5': 290.0, '37.5': 355.0, '41': 345.0, '38.5': 375.0, '36': 345.0, '36.5': 360.0, '48.5': 275.0, '40': 380.0, '48': 287, '49.5': 567, '50.5': 850, '51.5': 399, '49': 386}
or you could write it like this (to avoid a double merge when most keys are common):
{ **x, **{ k:v for k,v in y.items() if k not in x or x[k]<v} }
or, you could use a descending sort on the concatenation of (key,value) tuples but sorting the whole data just to get minimums between matching keys is going to be very inefficient:
dict(sorted((*x.items(),*y.items()),key=lambda i:-i[1]))
If you are not comfortable with dictionary comprehensions, you could use a simple for loop:
merged = x.copy()
for k,v in y.items(): merged[k] = min(v, merged.get(k,v))
Upvotes: 1
Reputation: 3844
I believe this will meet your requirements. It's much simpler as it uses sets of keys so that set1.intersection(set2)
contains all of the keys in both sets, so it can use this to make the comparisons, and set2-set1
just contains those unique to set2
, so they can simply be moved to set1
def compare_prices(dict1,dict2):
temp1 = ast.literal_eval(dict1)
temp2 = ast.literal_eval(dict2)
set1 = set(temp1.keys())
set2 = set(temp2.keys())
for k in set1.intersection(set2):
if temp1[k] > temp2[k]:
temp1[k] = temp2[k]
for k in set2 - set1:
temp1[k] = temp2[k]
return dict(sorted(temp1.items()))
Output is:
print(compare_prices(x, y))
{'36': 345.0, '36.5': 360.0, '37.5': 355.0, '38': 375.0, '38.5': 375.0, '39': 370.0, '40': 380.0, '40.5': 395.0, '41': 345.0, '42': 300.0, '42.5': 230.0, '43': 220.0, '44': 220.0, '44.5': 220.0, '45': 220.0, '45.5': 290.0, '46': 225.0, '47': 300.0, '47.5': 265.0, '48': 287, '48.5': 275.0, '49': 386, '49.5': 567, '50.5': 850, '51.5': 399}
Upvotes: 1