Home > other >  How do I flip all zeroes and ones in a number, but only 1 digit at a time in Python3?
How do I flip all zeroes and ones in a number, but only 1 digit at a time in Python3?

Time:07-16

e.g. when 1010 is the given number, i want it to output:

0010
1110
1000
1011

I have tried to do it without imports to challenge myself. I've tried to put each number in a list and flip each digit accordingly. I get stuck when it doesn't update the first number. It outputs:

0010
0110
0000
0011

CodePudding user response:

Binary numbers represent a number as a sum of powers of 2 written from right to left (just like decimal numbers represent a number as a sum of powers of 10 written from right to left).

If you get your value as a string ('1010') you can turn it into an integer, if you get it as an integer (0b1010) you of course wouldn't need to:

value = '1010'
x = int(value, 2)  # interpret string as binary

a = 1
while a < x:
    print(x ^ a, '{0:04b}'.format(x ^ a))
    a = a * 2

This line:

print(x ^ a, '{0:04b}'.format(x ^ a))

It prints x ^ a, which is the logical XOR of x and a, meaning that it will have a 1 wherever x and a are different, and 0 elsewhere. Since a will be a power of 2, it will only have 1 bit set to 1, and so it will flip just that bit.

The second part starts with '{0:04b}', which will format the same value as binary, using 4 positions.

If you don't like that it's reversed, you'd need to know where to start (i.e. the greatest power of 2 that still fits into the number), but that is a given if you know the length of the string you want:

value = '1010'
x = int(value, 2)  # interpret string as binary

for a in range(len(value)-1, -1, -1):
    print(x ^ 2**a, '{0:04b}'.format(x ^ 2**a))

Or, as a one-liner:

value = '1010'
print(' '.join(f'{int(value, 2) ^ 2**a:04b}' for a in range(len(value)-1, -1, -1)))

These two examples loop through powers of 2, starting at the greatest power of two that fits inside the starting value, down to 2^0 (1) and perform the same trick as before.

The one-liner then also puts the results together with spaces, as in your example.

Outputs:

2 0010
14 1110
8 1000
11 1011

0010 1110 1000 1011

CodePudding user response:

The simple solution is to convert string to list, replace the required index and convert it back to the string.

s = "1010"
res = []
for i in range(0, len(s)):
    t = list(s)
    t[i] = '1' if t[i] == '0' else '0'
    res.append(''.join(t))
print(res) #['0010', '1110', '1000', '1011']

CodePudding user response:

N = 345678909876543223456
for i in range(N.bit_length()):
   print(N^(1<<i))

You can use simple bitwise operators:

^ is Xor, basically bit^1 flips the bit

<< is a left shift, basically 1<<N appends N zero in front of the bit -> 1000...Ntimes

CodePudding user response:

Since Grismar brought up efficiency, here's a benchmark on a longer string ('1010' * 3000) with two more solutions:

 210 ms  Grismar1
 345 ms  Grismar2
2043 ms  Akshay
  52 ms  Kelly1
  13 ms  Kelly2

For better comparison I made all solutions generators that yield the strings.

Full code (Try it online!):

def Kelly1(s):
    for i, c in enumerate(s):
        yield s[:i]   ('1' if c == '0' else '0')   s[i 1:]

def Kelly2(s):
    bs = bytearray(s, 'ascii')
    for i, b in enumerate(bs):
        bs[i] ^= 1
        yield bs.decode()
        bs[i] = b

def Grismar1(value):
    x = int(value, 2)  # interpret string as binary
    a = 1
    while a <= x:
        yield'{0:04b}'.format(x ^ a)
        a = a * 2

def Grismar2(value):
    x = int(value, 2)  # interpret string as binary
    for a in range(len(value)-1, -1, -1):
        yield'{0:04b}'.format(x ^ 2**a)

def Akshay(s):
    for i in range(0, len(s)):
        t = list(s)
        t[i] = '1' if t[i] == '0' else '0'
        yield ''.join(t)

funcs = Grismar1, Grismar2, Akshay, Kelly1, Kelly2

for f in funcs:
    print(*f('1010'), f.__name__)

from timeit import repeat
from collections import deque

for f in funcs * 2:
    value = '1010' * 3000
    t = min(repeat(lambda: deque(f(value), 0), number=1))
    print('M ms ' % (t * 1e3), f.__name__)
  • Related