I would like to define a defaultdict
that returns the value of the largest key, if the key that I am providing is not in the dictionary. Basically I am looking for a way to store config information with the twist, that values default to their last defined values.
My implementation is as follows:
from collections import defaultdict
d = defaultdict(lambda: d[max(d.keys())])
d.update({2010: 10, 2011: 20, 2013: 30 })
for year in [2010, 2011, 2013, 2014]:
print(f"{year}: {d[year]}")
which correctly produces:
2010: 10
2011: 20
2013: 30
2014: 30
(a more elaborate version could also return values for keys smaller than the smallest).
Is there a more elegant way to define the lambda function without the requirement that you know the dictionary's name?
Calculating frequently the max key looks quite inefficient because in Python keys are in hash maps so they aren't sorted.
Consider writing your own default_dict:
class DictLast(collections.MutableMapping,dict):
def __init__(self, *args, **kwargs):
self.theMaxKey = None
self.update(*args, **kwargs)
def __getitem__(self, key):
if dict.__contains__(self,key):
return dict.__getitem__(self,key)
return dict.__getitem__(self, self.theMaxKey)
def __setitem__(self, key, value):
if self.theMaxKey is None:
self.theMaxKey = key
if key > self.theMaxKey:
self.theMaxKey = key
dict.__setitem__(self,key,value)
d = DictLast()
d.update({2010: 10, 2011: 20, 2013: 30 })
for year in [2010, 2011, 2013, 2014]:
print(f"{year}: {d[year]}")
please notice that, whenever asked for a missing key, my implementation doesn't add the key to the dictionary. I assume this is the intended behavior
If you are in doubt, try this code with my and your implementation:
for year in [2010, 2011, 2013, 2015]:
print(f"{year}: {d[year]}")
d[2014]=7
for year in [2010, 2011, 2013, 2015]:
print(f"{year}: {d[year]}")
to understand what's the difference
EDIT: As pointed out in the comments below:
"this strategy only works if you don't remove items from the dictionary".
IMO If you want the data structure to be well designed you should manage removal too (up to you to decide if you want to raise, recalculate the max or do something different).