Reputation: 862
I have a nested dict in the form of :
dict : {
NAME1 :{
FIELDS :{
FIELD1 :{
MAXBIT:2, MINBIT:0},
FIELD2 :{
MAXBIT:4, MINBIT:3},
FIELD3 :{
MAXBIT:7, MINBIT:5}}}
NAME2
....
}
I want to write a function that takes a NAME
and a hex
value, and returns binary decomposition of hex
according to dict
.
Example:
for input f(NAME1, 0x0f)
(0x0f
is 00001111) and the above dict, output will be:
NAME1:
FIELD1: 111
FIELD2: 01
FIELD3: 000
binary string is composed of fields, each field has it's length in bits. pretty printing is not important, I'm just looking for the pythonic way to do it. Here's what I wrote:
def f(name1, hex_value):
fields = []
for field, value in dictionary[name1]['FIELDS'].items():
fields.append([value['MINBIT'], value['MAXBIT'], field])
fields.sort()
binary_string = '{0:b}'.format(int(hex_value, 16))
chunks = [bit_pair[1]-bit_pair[0]+1 for bit_pair in fields]
rev_bin_sring = reversed(binary_string)
sliced_fields = [''.join(islice(rev_bin_sring, i)) for i in chunks]
sliced_fields = [string.replace('', '0') for string in sliced_fields]
final_res = [list((field[2], bin_value)) for bin_value, field in zip(sliced_fields, fields)]
but it looks pretty ugly, I'm sure there's a more elegant way.
Upvotes: 1
Views: 157
Reputation: 5213
I've renamed your dict
as d
since dict
is a builtin python object type and you really shouldn't be overwriting those with your own variables:
d = {
'NAME1' :{
'FIELDS' :{
'FIELD1' :{
'MAXBIT':2, 'MINBIT':0},
'FIELD2' :{
'MAXBIT':4, 'MINBIT':3},
'FIELD3' :{
'MAXBIT':7, 'MINBIT':5}}}}
def f(name, hex_value):
fields = d[name]['FIELDS']
bin_value = bin(hex_value).replace('b','0')[::-1]
new_d = {name:{}}
for field, value in fields.items():
max_b, min_b = value['MAXBIT']+1, value['MINBIT']
bin_value += '0'*(max_b-len(bin_value))
new_d[name][field] = bin_value[min_b:max_b][::-1]
return new_d
This first gets the relevant fields based on the name
argument from the dictionary d
. Then it uses the bin
function to convert the hex_value
to a binary representation (as a string). The first two characters of bin_value
will be 0b
so replace the b
with another 0
and reverse the string (this will allow you to get your values using string slices later on). Now, for each MAXBIT
, MINBIT
pair you can slice your bin_value
string and then reverse it (using [::-1]
) to get your intended decomposition. Obviously this will fail if your bin_value
is shorter than the max_b
value. To accommodate this, you can pad extra '0'
s on the end of bin_value
so that bin_value
is at least max_b
characters long. Also note that max_b = value['MAXBIT'] + 1
since you want to include the character at the index of max_b
but python slices exclusively, so you add 1
.
>>> f('NAME1',0x0f)
{'NAME1': {'FIELD1': '111', 'FIELD2': '01', 'FIELD3': '000'}}
EDIT
A slightly different alternative that doesn't require all that reversing back and forth:
def f(name, hex_value):
fields = d[name]['FIELDS']
bin_value = bin(hex_value).replace('b','0')
new_d = {name:{}}
for field, value in fields.items():
max_b, min_b = value['MAXBIT']+1 , value['MINBIT']
new_d[name][field] = bin_value.zfill(max_b)[-max_b:-min_b or None]
return new_d
>>> f('NAME1',0x0f)
{'NAME1': {'FIELD1': '111', 'FIELD2': '01', 'FIELD3': '000'}}
Note: the value['MINBIT'] or None
handles the case where value['MINBIT']
is zero.
Upvotes: 1