tags:

views:

144

answers:

2

I have a function that returns an 8 digit long binary string for given parameter:

def rule(x):
rule = bin(x)[2:].zfill(8)
return rule

I want to traverse each index of this string and check if it is a zero or a one. I tried to write a code like this:

def rule(x):
   rule = bin(x)[2:].zfill(8)
   while i < len(rule(x)):
         if rule[i] == '0'
            ruleList = {i:'OFF'}
         elif rule[i] == '1'
           ruleList = {i:'ON'}
         i = i + 1
    return ruleList

This code doesn't work. I am getting "Error: Object is unsubscriptable". What I am attempting to do is write a function that takes the following input, for example:

Input: 30
1. Converts to '00011110' (So far, so good)..
2. Checks if rule(30)[i] is '0' or '1' ('0' in this case where i = 0) 
3. Then puts the result in a key value pair, where the index of the
string is the key and the state (on
or off) is the value. 
4. The end result would be 'ruleList', where print ruleList
would yield something like this:
{0:'Off',1:'Off',2:'Off',3:'On',4:'On',5:'On',6:'On',7:'Off'}

Can someone help me out? I am new to python and programming in general so this function has proven to be quite challenging. I would like to see some of the more experienced coders solutions to this particular problem.

Thanks,

A: 

Here's a much more Pythonic version of the code you've written - hopefully the comments explain the code well enough to understand.

def rule(x):
    rule = bin(x)[2:].zfill(8)
    ruleDict = {} # create an empty dictionary
    for i,c in enumerate(rule): # i = index, c = character at index, for each character in rule
        # Leftmost bit of rule is key 0, increasing as you move right
        ruleDict[i] = 'OFF' if c == '0' else 'ON' 
        # could have been written as:
        # if c == '0':
        #    ruleDict[i] = 'OFF'
        # else:
        #    ruleDict[i] = 'ON'

        # To make it so ruleDict[0] is the LSB of the number:
        #ruleDict[len(rule)-1-i] = 'OFF' if c == '0' else 'ON' 
    return ruleDict

print rule(30)

Output:

$ python rule.py
{0: 'OFF', 1: 'ON', 2: 'ON', 3: 'ON', 4: 'ON', 5: 'OFF', 6: 'OFF', 7: 'OFF'}

The output actually happens to be printed in reverse order, because there is no guarantee that a dictionary's keys will be printed in any particular order. However, you will notice that the numbers correspond where the largest number is the most significant bit. That's why we had to do the funny business of indexing ruleDict at len(rule)-1-i.

Mark Rushakoff
the OP wants "the index of the string is the key" so it should be ruleDict[i] = 'OFF' if c == '0' else 'ON'
newacct
Bits are almost always indexed with 0 as the rightmost bit - I'm guessing he just wasn't aware of that, and that's why he counted with 0 as the rightmost. Numbers make more sense when the highest bit index is the leftmost / most significant. Anyway, I added a paragraph onto the end right around the same time you left the comment.
Mark Rushakoff
Whoever came up with that ternary syntax needs to be shot. It's easily among the ugliest, most nonsensical things in Python.
Glenn Maynard
@Glenn: it beat out 15 other ternary syntax proposals in PEP308 (choice key near bottom) http://www.python.org/dev/peps/pep-0308/
Mark Rushakoff
Thanks for this code. As I said, I'm still learning and this is very useful. Can you please explain why it is necessary to output ruleDict in reverse order? And is there a way to output ruleDict in the normal order? Thanks.
AME
@unknown: I've updated the code to hopefully clarify the difference between the two.
Mark Rushakoff
+2  A: 

Is this what you want?

def rule(x) :
    rule = bin(x)[2:].zfill(8)
    return dict((index, 'ON' if int(i) else 'OFF') for index, i in enumerate(rule))
sykora
Or, in Python 3: `return {index: 'ON' if int(i) else 'OFF' for index, i in enumerate(rule)}`
newacct
heh, it's usually me who provides the python 3 answers first, just this time I went with the standard 2.x one. You're right, of course.
sykora
No need to int() or booleanize these characters, there are only 2 to choose from. Why not: dict((index, {'0':'OFF', '1':'ON'}[i]) for index, i in enumerate(rule)) (and of course, the Py3 dict comprehension variation)?
Paul McGuire
This code works but I don't understand how it is determining whether each number in the string is either a 1 or a 0. Can someone please explain it to me?
AME
@Paul McGuire: Both are valid approaches, I prefer the if/else because it's more explicit.
sykora