Reputation: 28336
I have a dictionary like this:
dict = {
"AA": {"Rad": 1000.0, "Code": "C01"},
"BB": {"Rad": 2200.0, "Code": "C02"},
"CC": {"Rad": 2300.0, "Code": "C02"},
"DD": {"Rad": 3000.0, "Code": "C04"}
}
Most of the time, selecting the appropriate value is quite simple. My code grabs the value from the dictionary entry by passing in the key and the property I need. For example, if my value is "CC", I get the code with dict["CC"]["Code"]
. Simple enough and works the vast majority of the time.
Now, I need to adjust for a change in the business logic. If I follow what I've done in the past, the dictionary will look like this:
dict = {
"AA": {"Rad": 1000.0, "Code": "C01"},
"BB": {"Rad": 2200.0, "Code": "C02"},
"CC": {"Rad": 2300.0, "Code": "C02"},
"DD": {"Rad": 3000.0, "Code": "C04"},
"DD": {"Rad": 7000.0, "Code": "C03"}
}
But this doesn't work. Two identical keys in a dictionary doesn't work. This is problem one.
The other issue, I need to take into account the value of Rad
when selecting a Code
. Rad is a minimum value used for comparison. If the value in my variable is greater than Rad
use corresponding the Code
value.
How do I restructure this to accommodate value retrieval by dictionary key (the majority of what this code does) and retrieval by key
& Rad
value? If necessary, I can through out this dictionary structure and do something different.
Update 2: Refining the business logic a bit. The rad values specified in the dictionary are minimum values. I need to grab the smallest value that is greater than the minimum value regardless of the order in which they are listed in the dictionary.
In the following case,
"DD": [{"Rad": 3000.0, "Code": "C04"},
{"Rad": 7000.0, "Code": "C03"},
{"Rad": 4000.0, "Code": "C09"}]]
get(d, "DD", 5000)
returns C04
but C09
is expected.
Update 1: A database of any kind is way overkill for this project. This dictionary will, at most, have six entries.
Here is the minimal code to demonstrate what I'm trying to do.
dict = {
"AA": {"Rad": 1000.0, "Code": "C01"},
"BB": {"Rad": 2200.0, "Code": "C02"},
"CC": {"Rad": 2300.0, "Code": "C02"},
"DD": {"Rad": 3000.0, "Code": "C04"},
"DD": {"Rad": 7000.0, "Code": "C03"}
}
type = "DD"
rad = 4000
# need to incorporate rad variable
print dict["type"]["Code"]
# Should print C04
Upvotes: 3
Views: 607
Reputation: 919
You can write a custom type class to do that.
import itertools
import bisect
class cdict(dict):
def __init__(self, data=None):
dict.__init__(self)
if data: self.update(data)
def __call__(self,base,target):
res = self.get(base) if base else None
_st = res.items() if isinstance(res,dict) else res
if isinstance(res,dict):
if res and target:
_item = res['Rad']
if target >= _item: return res['Code']
elif isinstance(res,list):
_iter = sorted ( filter (lambda x: not isinstance(x,str),list (itertools.chain.from_iterable(map(lambda x: x.values(),res)))))
if len(res) and target:
_filter = filter (lambda x: x <= target,_iter)
_sorted = bisect.bisect(_filter,target)
if len(_filter) and not _sorted: return filter (lambda x: x['Rad'] == _iter [ _sorted ],res)[0]['Code']
elif len(_filter) and _sorted: return filter (lambda x: x['Rad'] == _iter [ _sorted -1 ],res)[0]['Code']
return None
x = cdict({
"AA": {"Rad": 1000.0, "Code": "C01"},
"BB": {"Rad": 2200.0, "Code": "C02"},
"CC": {"Rad": 2300.0, "Code": "C02"},
"DD": [ {"Rad": 7000.0, "Code": "C04"}, {"Rad": 3000.0, "Code": "C03"} ] } )
print x('AA',2000.0)
print x('DD',8000.0)
print x('DD',4000.0)
C01 C04 C03
Upvotes: 0
Reputation: 82929
You could make the values in your dictionary lists, so one key can be mapped to multiple values.
d = {
"AA": [{"Rad": 1000.0, "Code": "C01"}],
"BB": [{"Rad": 2200.0, "Code": "C02"}],
"CC": [{"Rad": 2300.0, "Code": "C02"}],
"DD": [{"Rad": 3000.0, "Code": "C04"}, {"Rad": 7000.0, "Code": "C03"}]
}
For getting the code
from the list satisfying the rad
constraint, you could try this:
def get(d, t, r):
try:
return max((x for x in d[t] if x["Rad"] < r), key=lambda x: x["Rad"])["Code"]
except ValueError:
return None
Example:
>>> get(d, "DD", 4000)
C04
Upvotes: 1
Reputation: 276
Are the sub-dictionaries always going to have the same two fields? If so, you could place the "Rad" and "Code" fields into a tuple, then put the tuples into a list, like:
dict = {
"AA": [(1000.0, "C01")]
...
"DD": [(3000.0,"C04"), (7000.0, "C03")]
}
To access the "Code" field of the first entry for the "DD" field, use:
dict["DD"][0][1]
Upvotes: 1
Reputation: 1238
One way to do this is to structure your dictionary like this:
dict = {
"AA": {1000.0: "C01"},
"BB": {2200.0: "C02"},
"CC": {2300.0: "C02"},
"DD": {3000.0: "C04",
7000.0: "C03"},
}
Then to get a the Code
field, you can write dict["AA"][1000.0]
.
Upvotes: 2
Reputation: 24774
dict = {
...
"DD": {4000:{"code":"C04"}, 7000: {"Code": "C03"}}
}
Upvotes: 0