How to get an array of all possible binary numbers given a binary number of the same length
Question:
-
goal: I have a string which usually looks like this "010" and I need to replace the zeros by 1 in all the possible ways like this ["010", "110", "111", "011"]
-
problem when I replace the zeros with 1s I iterate through the letters of the string from left to right then from right to left. As you can see in the code where I did number = number[::-1]
. Now, this method does not actually cover all the possibilities.
-
I also need to maybe start from the middle or maybe use the permutation method But not sure how to apply in python.
- mathematically there is something like
factorial of the number of places/(2)!
A = '0111011110000'
B = '010101'
C = '10000010000001101'
my_list = [A,B,C]
for number in [A,B,C]:
number = number[::-1]
for i , n in enumerate(number):
number = list(number)
number[i] = '1'
number = ''.join(number)
if number not in my_list: my_list.append(number)
for number in [A,B,C]:
for i , n in enumerate(number):
number = list(number)
number[i] = '1'
number = ''.join(number)
if number not in my_list: my_list.append(number)
print(len(my_list))
print(my_list)
Answers:
Well, you will definitely get other answers with a traditional implementations of combinations with fixed indexes, but as we’re working with just "0" and "1", you can use next hack:
source = "010100100001100011"
pattern = source.replace("0", "{}")
count = source.count("0")
combinations = [pattern.format(*f"{i:0{count}b}") for i in range(1 << count)]
Basically, we count amount of zeros in source, then iteration over range where limit is number with this amount of set bits and unpack every number in binary form into a pattern.
It should be slightly faster if we predefine pattern for binary transformation too:
source = "010100100001100011"
pattern = source.replace("0", "{}")
count = source.count("0")
fmt = f"{{:0{count}b}}"
result = [pattern.format(*fmt.format(i)) for i in range(1 << count)]
Upd. It’s not clear do you need to generate all possible combinations or just get number, so originally I provided code to generate them, but if you will look closely in my method I’m getting number of all possible combinations using 1 << count
, where count
is amount of '0'
chars in source string. So if you need just number, code is next:
source = "010100100001100011"
number_of_combinations = 1 << source.count("0")
Alternatively, you can also use 2 ** source.count("0")
, but generally power is much more slower than binary shift, so I’d recommend to use option I originally advised.
You can use separate out the zeros and then use itertools.product
–
from itertools import product
x = '0011'
perm_elements = [('0', '1') if digit == '0' else ('1', ) for digit in x]
print([''.join(x) for x in product(*perm_elements)])
['0011', '0111', '1011', '1111']
If you only need the number of such combinations, and not the list itself – that should just be 2 ** x.count('0')
Based on your objective you can do this to obtain the expected results.
A = '0111011110000'
B = '010'
C = '10000010000001101'
my_list = [A, B, C]
new_list = []
for key, number in enumerate(my_list):
for key_item, num in enumerate(number):
item_list = [i for i in number]
item_list[key_item] = "1"
new_list.append(''.join(item_list))
print(len(new_list))
print(new_list)
For each position in the string that has a zero, you can either replace it with a 1 or not. This creates the combinations. So you can progressively build the resulting list of strings by adding the replacements of each ‘0’ position with a ‘1’ based on the previous replacement results:
def zeroTo1(S):
result = [S] # start with no replacement
for i,b in enumerate(S):
if b != '0': continue # only for '0' positions
result += [r[:i]+'1'+r[i+1:] for r in result] # add replacements
return result
print(zeroTo1('010'))
['010', '110', '011', '111']
If you’re allowed to use libraries, the product function from itertools can be used to combine the zero replacements directly for you:
from itertools import product
def zeroTo1(S):
return [*map("".join,product(*("01"[int(b):] for b in S)))]
The tuples of 1s and 0s generated by the product function are assembled into individual strings by mapping the string join function onto its output.
We also can use recursive solution for this problem, we iterate over string and if saw a "0" change it to "1" and begin another branch on this new string:
s = "010100100001100011"
def perm(s, i=0, result=[]):
if i < len(s):
if s[i] == "0":
t = s[:i]+"1"+s[i+1:]
result.append(t)
perm(t, i+1, result)
perm(s, i+1, result)
res = [s]
perm(s, 0, res)
print(res)
-
goal: I have a string which usually looks like this "010" and I need to replace the zeros by 1 in all the possible ways like this ["010", "110", "111", "011"]
-
problem when I replace the zeros with 1s I iterate through the letters of the string from left to right then from right to left. As you can see in the code where I did
number = number[::-1]
. Now, this method does not actually cover all the possibilities. -
I also need to maybe start from the middle or maybe use the permutation method But not sure how to apply in python.
- mathematically there is something like
factorial of the number of places/(2)!
- mathematically there is something like
A = '0111011110000'
B = '010101'
C = '10000010000001101'
my_list = [A,B,C]
for number in [A,B,C]:
number = number[::-1]
for i , n in enumerate(number):
number = list(number)
number[i] = '1'
number = ''.join(number)
if number not in my_list: my_list.append(number)
for number in [A,B,C]:
for i , n in enumerate(number):
number = list(number)
number[i] = '1'
number = ''.join(number)
if number not in my_list: my_list.append(number)
print(len(my_list))
print(my_list)
Well, you will definitely get other answers with a traditional implementations of combinations with fixed indexes, but as we’re working with just "0" and "1", you can use next hack:
source = "010100100001100011"
pattern = source.replace("0", "{}")
count = source.count("0")
combinations = [pattern.format(*f"{i:0{count}b}") for i in range(1 << count)]
Basically, we count amount of zeros in source, then iteration over range where limit is number with this amount of set bits and unpack every number in binary form into a pattern.
It should be slightly faster if we predefine pattern for binary transformation too:
source = "010100100001100011"
pattern = source.replace("0", "{}")
count = source.count("0")
fmt = f"{{:0{count}b}}"
result = [pattern.format(*fmt.format(i)) for i in range(1 << count)]
Upd. It’s not clear do you need to generate all possible combinations or just get number, so originally I provided code to generate them, but if you will look closely in my method I’m getting number of all possible combinations using 1 << count
, where count
is amount of '0'
chars in source string. So if you need just number, code is next:
source = "010100100001100011"
number_of_combinations = 1 << source.count("0")
Alternatively, you can also use 2 ** source.count("0")
, but generally power is much more slower than binary shift, so I’d recommend to use option I originally advised.
You can use separate out the zeros and then use itertools.product
–
from itertools import product
x = '0011'
perm_elements = [('0', '1') if digit == '0' else ('1', ) for digit in x]
print([''.join(x) for x in product(*perm_elements)])
['0011', '0111', '1011', '1111']
If you only need the number of such combinations, and not the list itself – that should just be 2 ** x.count('0')
Based on your objective you can do this to obtain the expected results.
A = '0111011110000'
B = '010'
C = '10000010000001101'
my_list = [A, B, C]
new_list = []
for key, number in enumerate(my_list):
for key_item, num in enumerate(number):
item_list = [i for i in number]
item_list[key_item] = "1"
new_list.append(''.join(item_list))
print(len(new_list))
print(new_list)
For each position in the string that has a zero, you can either replace it with a 1 or not. This creates the combinations. So you can progressively build the resulting list of strings by adding the replacements of each ‘0’ position with a ‘1’ based on the previous replacement results:
def zeroTo1(S):
result = [S] # start with no replacement
for i,b in enumerate(S):
if b != '0': continue # only for '0' positions
result += [r[:i]+'1'+r[i+1:] for r in result] # add replacements
return result
print(zeroTo1('010'))
['010', '110', '011', '111']
If you’re allowed to use libraries, the product function from itertools can be used to combine the zero replacements directly for you:
from itertools import product
def zeroTo1(S):
return [*map("".join,product(*("01"[int(b):] for b in S)))]
The tuples of 1s and 0s generated by the product function are assembled into individual strings by mapping the string join function onto its output.
We also can use recursive solution for this problem, we iterate over string and if saw a "0" change it to "1" and begin another branch on this new string:
s = "010100100001100011"
def perm(s, i=0, result=[]):
if i < len(s):
if s[i] == "0":
t = s[:i]+"1"+s[i+1:]
result.append(t)
perm(t, i+1, result)
perm(s, i+1, result)
res = [s]
perm(s, 0, res)
print(res)