Python - Flipping Binary 1's and 0's in a String
I'm trying to take a binary number in string form and flip the 1's and 0's, that is, change all of the 1's in the string to 0's, and all of the 0's to 1's. I'm new to Python and have been racking my brain for several hours now trying to figure it out.
>>> ''.join('1' if x == '0' else '0' for x in '1000110')
'0111001'
The a for b in c
pattern is a generator expression, which produces a series of items based on a different series. In this case, the original series is the characters (since you can iterate over strings in Python, which gives you the characters that make up that string), and the new series is a set of characters with the 0's and 1's flipped.
'1' if x == '0' else '0'
is pretty straightforward - it gives us whichever of 1
or 0
isn't x
. We do this for each such x
in the original set of characters, and then join()
them all together (with an empty string ''
, a.k.a. nothing, in between each item), thus giving us a final string which is all of the opposite characters from the original, combined.
Another way to do it is with string.translate()
and string.maketrans()
from string import maketrans
bitString = "10101010100011010"
flippedString = bitString.translate(maketrans("10","01"))
If speed is important:
And you already have the decimal integer representing the binary string, then bit manipulation is slightly faster.
bin((i ^ (2 ** (i.bit_length()+1) - 1)))[3:]
If you are only given the binary string, then use the str.replace
method given by @Amy:
s.replace('1', '2').replace('0', '1').replace('2', '0')
I tested the various methods proposed here, and the bit manipulation method, with this gist:
Test Results
i = 129831201;
s = '111101111010001000100100001';
Bit manipulation given decimal int
:
bin((i ^ (2 ** (i.bit_length()+1) - 1)))[3:]
1000000 loops, best of 3: 0.647 usec per loop
Bit manipulation given binary string:
bin((int(s, 2) ^ (2**(len(s)+1) - 1)))[3:]
1000000 loops, best of 3: 0.922 usec per loop
Sequential str.replace
:
s.replace('1', '2').replace('0', '1').replace('2', '0')
1000000 loops, best of 3: 0.619 usec per loop
str.maketrans
:
s.translate(str.maketrans('10', '01'))
1000000 loops, best of 3: 1.16 usec per loop
''.join
with dictionary mapping:
flip = {'1':'0', '0':'1'}; ''.join(flip[b] for b in s)
100000 loops, best of 3: 2.78 usec per loop
''.join
with conditional:
''.join('1' if b == '0' else '0' for b in s)
100000 loops, best of 3: 2.82 usec per loop
Amber's answer, while superior, possibly isn't the most clear, so here's a super basic iterative example:
b_string = "1100101"
ib_string = ""
for bit in b_string:
if bit == "1":
ib_string += "0"
else:
ib_string += "1"
print ib_string
This can be done in much better ways...replacements, comprehensions, but this is an example.
I would learn from the other answers in this question once you understand the basis of this one. This method is slow and painful. For the best performance, as Muhammad Alkarouri pointed out, the string.translate
/maketrans
combo is the way to go. Right behind it is the comprehension. My code is the slowest by a significant margin.
You've already marked an answer to this, but I haven't seen the method that I would prefer. I'm assuming here that you have a binary number of known length - 8 bits in the examples I am giving.
If you can start with the number as just a number, you can do the following:
myNumber = 0b10010011
myNumberInverted = myNumber ^ 0b11111111
The ^
operator performs a bitwise XOR.
If you really do have to start with a string, you can convert to an integer first and then perform this operation.
myString = '10010011'
myNumber = int(myString, 2)
myNumberInverted = myNumber ^ 0b11111111