Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

This does the job, but is not especially elegant.

What is the preferred Pythonic idiom to my childish nests?

def bytexor(a, b):
    res = ""
    for x, y in zip(a, b):
        if (x == "1" and y == "0") or (y =="1" and x == "0"):
            res += "1"
        else:
            res += "0"

    return res

def get_all():
    res = []
    bit = ["0","1"]
    for i in bit:
        for j in bit:
            for k in bit:
                for l in bit:
                    res.append(i+j+k+l)
    return res

if __name__=="__main__":

    for k0 in get_all():
        for k1 in get_all():
            for k2 in get_all():
                for k3 in get_all():
                    for k4 in get_all():
                        if bytexor(bytexor(k0, k2), k3) == "0011":
                            if bytexor(bytexor(k0, k2), k4) == "1010":
                                if bytexor(bytexor(bytexor(k0,k1),k2),k3) == "0110":
                                    print k0, k1, k2, k3, k4
                                    print bytexor(bytexor(bytexor(k0, k1),k2),k4)
share|improve this question
    
What is the code supposed to be doing? You're apparently trying to get all combinations of 4-bit binary numbers... but what are you trying to get from that? –  Jeff Mercado Nov 20 '12 at 7:52
    
@JeffMercado the problem was homework. There was an encryption algorithm given and some sample cyphertext - this code does an exhaustive search for keys that fit with the ciphertext, and encrypts a message using the same algorithm for each valid key. –  trideceth12 Nov 20 '12 at 10:31
    
I know this is not really what you were looking for, but you could leave the loops and optimize their runtime using cython or numba. –  yoavram Nov 27 '12 at 14:00
add comment

4 Answers 4

up vote 26 down vote accepted

To convert an integer to a bit string with a particular number of digits, use string.format with the b format type. For example:

>>> ['{0:04b}'.format(i) for i in range(16)]
['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111',
 '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']

But really it looks to me as though you don't want to be working with bit strings at all. You just want to be working with integers.

So instead of get_all, just write range(16) and instead of bytexor, write ^. Your entire program can be written like this:

from itertools import product
for a, b, c, d, e in product(range(16), repeat=5):
    if a ^ c ^ d == 3 and a ^ c ^ e == 10 and a ^ b ^ c ^ d == 6:
        print a, b, c, d, e, a ^ b ^ c ^ e

(This will also run a lot faster without all that fiddling about with strings.)

share|improve this answer
    
Thanks.. I can't believe it took me all that to write what could be done with five lines :s –  trideceth12 Nov 20 '12 at 16:11
add comment

Depending on what you are ultimately doing, probably the neatest way is to use a standard module, itertools. Using get_all as an example:

import itertools

def get_all_bitpatterns():
    res = []
    bit = [ "0", "1" ]
    for z in itertools.product( bit, bit, bit, bit ):
        res.append( "".join(z) )
    return res
share|improve this answer
2  
product takes a repeat argument, which would be useful here. –  Gareth Rees Nov 20 '12 at 12:06
2  
You could also use bit = '01' as string is iterable in Python. –  Developer Nov 20 '12 at 12:14
4  
return ["".join(z) for z in itertools.product(bit, repeat=4)] –  tokland Nov 20 '12 at 13:30
add comment

This is just a little bit improved edition of 'Glenn Rogers' answer ;) Simply work around bit, say bit='abcd' and number n.

from itertools import product

def AllBitPatterns(bit='01',n=2):
    out = []
    for z in product(bit,repeat=n*len(bit)):    #thanks to a comment
        out.append(''.join(z))
    return out

print AllBitPatterns()
print AllBitPatterns(n=3)
print AllBitPatterns(bit='-~')

Outputs:

>>> 
['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']
['000000', '000001', '000010', '000011', '000100', '000101', '000110', '000111', '001000', '001001', '001010', '001011', '001100', '001101', '001110', '001111', '010000', '010001', '010010', '010011', '010100', '010101', '010110', '010111', '011000', '011001', '011010', '011011', '011100', '011101', '011110', '011111', '100000', '100001', '100010', '100011', '100100', '100101', '100110', '100111', '101000', '101001', '101010', '101011', '101100', '101101', '101110', '101111', '110000', '110001', '110010', '110011', '110100', '110101', '110110', '110111', '111000', '111001', '111010', '111011', '111100', '111101', '111110', '111111']
['----', '---~', '--~-', '--~~', '-~--', '-~-~', '-~~-', '-~~~', '~---', '~--~', '~-~-', '~-~~', '~~--', '~~-~', '~~~-', '~~~~']
share|improve this answer
add comment

I have answered awhile ago to this very type of question. This is a very simple problem. You should not complicate it at all with iterators.

The trick is that the bit pattern you are seeking for is actually the bits of numbers incremented by 1!

Something like:

def get_all():
    res = []
    for i in range(16):
        # get the last four bits of binary form i which is an int
        bin(i) # a string like '0b0000' - strip '0b', 0 pad it to 4 length

I am not really the python guy, but I hope the idea is clear. Equivalent Java code:

int len = 3; // your number of for loops
int num = (int)Math.pow(2, len);
for(int i=0; i<num; i++){
    // http://stackoverflow.com/a/4421438/1273830
    System.out.println(String.format("%"+len+"s", Integer.toBinaryString(i)).replace(' ', '0'));
}

Happy coding.

share|improve this answer
1  
why the downvote? –  Prasanth Nov 20 '12 at 13:34
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.