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)

Asked By: Ali Husham

||

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.

Answered By: Olvin Roght

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')

Answered By: Mortz

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)
Answered By: kitou09

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.

Answered By: Alain T.

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)
Answered By: S4eed3sm
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.