10

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.

2
  • You've already marked an answer to this, but you may want to look at struct.pack and unpack Commented Oct 13, 2010 at 20:37
  • wrack (v) to destroy; rack (v) to torture Commented Jan 4, 2012 at 16:22

10 Answers 10

33
>>> ''.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.

Sign up to request clarification or add additional context in comments.

1 Comment

To make it too clever by half, you may elect to replace the if expression with '01'[x=='0']. I still prefer your answer, but thought I would mention it.
15

Another way to do it is with string.translate() and string.maketrans()

from string import maketrans
bitString = "10101010100011010"
flippedString = bitString.translate(maketrans("10","01"))

3 Comments

You might want to link to documentation slightly more recent than Python 2.3 - perhaps docs.python.org/library/string.html#string.translate
Didn't even notice I was linking to such old documentation, thanks.
To be perfectly correct, you're (correctly) using this method: docs.python.org/library/stdtypes.html#str.translate not the deprecated string function Amber linked to.
8

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

1 Comment

On my laptop the bit manipulation solution is faster than the sequential solution. s = "0101010101010010101000101011101011101011010" %timeit bin((int(s, 2) ^ (2**(len(s)+1) - 1)))[3:] 1000000 loops, best of 3: 495 ns per loop %timeit s.replace('1', '2').replace('0', '1').replace('2', '0') 1000000 loops, best of 3: 690 ns per loop
8

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

Comments

6

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.

4 Comments

I'd like to avoid encouraging people to use += for strings, as opposed to join() - not only is join() more Pythonic, but it's also the more efficient method for general usage. It's a good habit to instill early.
After a while working with Python one tends to find list comprehensions as clear or clearer than for loops.
I personally prefer the comprehension, it makes more sense to me.
Generally, don't speculate in timing. In this case, timeit ''.join('1' if x == '0' else '0' for x in b_string) gives 5.3 microseconds on my machine, while timeit b_string.translate(maketrans("10", "01")) gives 979 nanoseconds.
2

http://docs.python.org/library/string.html#string.replace

Replace all the 1's with 2's, then replace the 0's with 1's, finally replacing the 2's with 0's.

"10011".replace("1", "2").replace("0", "1").replace("2", "0")

Comments

2

Using a dictionary should be very straightforward.

>>> flip={"1":"0","0":"1"}
>>> s="100011"
>>> import sys
>>> for i in s:
...   sys.stdout.write(flip[i])
...
011100

Comments

0

Along the lines of Amber, but using ASCII arithmetic (for no particular reason). This obviously isn't meant for production code.

''.join(chr(97 - ord(c)) for c in my_bit_string)

48 and 49 are the ASCII (and Unicode) values for '0' and '1' respectively. ord gives you the numeric value for a character, while chr does the reverse.

1 Comment

Depending on your goal (in my case golfing, this can be a good answer, cheers.
0

Some things have changed since this question was answered. Hopefully my update proves useful to someone.

The translate method is the fastest for me. Full test code follows.

Thank you to those who contributed previously to allow me to test this.

# System & Software
# core i7 4790k @ ~ 4.6 GHz   32 GB RAM   Samsung Evo NVME
# Visual Studio 2019 16.3.6

# I do not understand Will's bit manipulation code
# worst times shown in comments
# ordered by speed on my system

import timeit # required to use timeit
import string # Required to call maketrans function.

# https://www.afternerd.com/blog/timeit-multiple-lines/
# if you are trying to time slightly longer pieces of code than a single line
# timeit wants a string


# the syntax  b_string.translate(maketrans("10", "01"))
# presented by Muhammad Alkarouri does not appear to be valid anymore
# i suspect this is due to changes within python versions
a1_bit_flip = """\
a1 = 0b1101010001101111 # accepts the binary input but will store it as an int
a1_bin = bin(a1)[2:]
# creates a string of the binary form of the integer minus the first 2 characters
flip_bin_a1 = a1_bin.translate(str.maketrans("10","01"))"""

trans_time = timeit.timeit(a1_bit_flip, number=100000) # time 100k iterations
print('translate time')
print(trans_time / 100000)
# determine average time of a single iteration ~ 0.6282 us
print('\n')



a2_bit_flip = """\
a2 = 0b1101010001101111
a2_bin = bin(a2)[2:]
a2_bin.replace('1', '2').replace('0', '1').replace('2', '0')"""

replace_time = timeit.timeit(a2_bit_flip, number=100000) # time 100k iterations
print('replace time')
print(replace_time / 100000)
# determine average time of a single iteration ~ 0.7557 us
print('\n')



a3_bit_flip = """\
a3 = 0b1101010001101111
a3_bin = bin(a3)[2:]
bin((int(a3_bin, 2) ^ (2**(len(a3_bin)+1) - 1)))[3:]"""
# I do not understand this line (Will)

bin_bit_time = timeit.timeit(a3_bit_flip, number=100000)
# time 100k iterations
print('bin_bit time')
print(bin_bit_time / 100000)
# determine average time of a single iteration ~ 1.14 us
print('\n')



a4_bit_flip = """\
a4 = 0b1101010001101111
a4_bin = bin(a4)[2:]
bin((i ^ (2 ** (i.bit_length()+1) - 1)))[3:]"""
# I do not understand this line (Will)

int_bit_time = timeit.timeit(a3_bit_flip, number=100000) # time 100k iterations
print('int_bit time')
print(int_bit_time / 100000)
# determine average time of a single iteration ~ 1.14 us
print('\n')



join_bit_flip = """\
a0 = 0b1101010001101111 # accepts the binary input but will store it as an int
a0_bin = bin(a0)[2:]
# creates a string of the binary form of the integer minus the first 2 characters
flip_a0 = "".join('1' if x == '0' else '0' for x in a0_bin)""" # (Amber)

join_time = timeit.timeit(join_bit_flip, number=100000) # time 100k iterations
print('join time')
print(join_time / 100000)
# determine average time of a single iteration ~ 14.511 us
print('\n')

1 Comment

Thanks for leaving the answer! It may be helpful to provide a more detailed answer directly explaining what you've found to be the quickest method, and then maybe provide the longer block of code at the end for reference. Just providing a long block of code with the explanation in inline comments adds a lot of extra work to determine what you're suggesting as the best method.
0
def flip_bits(flip_my_bits:int):
    #E.g bin:'1011011', decimal:91
    temp = flip_my_bits

    # Count significant figures
    # For '1011011' this should be 7
    # Essentially math.floor(math.log(i, 2)+1)
    bit_len = 0 
    while temp:
        bit_len+=1
        temp>>=1 

    # mask will be 111111
    mask= (1 << bit_len) - 1

    #     1011011
    #     1111111
    # xor:0100100
    return flip_my_bits ^ mask 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.