Reputation: 132
I have to generate all the possible binary representations of a given string, where some characters are "?" and others are 1 or 0.
I'm trying to do a recursive search but I encounter some weird problems I can't figure out.
userInput = list(input())
anslist = []
def fill(inp):
#print(inp)
if inp.count("?") == 0:
print(inp, "WAS ADDED")
anslist.append(inp)
return
for a in range(0, len(userInput)):
if inp[a] == "?":
inp[a] = 1
fill(inp)
inp[a] = 0
fill(inp)
return
print(anslist)
For the input ?01?1 I should be getting: 00101, 00111, 10101 and 10111 but I get 10111 10101 00101 printed out. In addition, anslist isn't working properly. I just can't seem to figure this out.
Upvotes: 3
Views: 221
Reputation: 41905
A simple solution that avoids using a global or a library:
def fill(digits):
if not digits:
return []
first, *rest = digits
strings = fill(rest) if rest else ['']
if first == '?':
return ['0' + string for string in strings] + ['1' + string for string in strings]
return [first + string for string in strings]
userInput = input()
print(fill(userInput))
Tries to spell things out rather than make the most efficient array operations, which is left as an exercise for the OP.
OUTPUT
> python3 test.py
?01?1
['00101', '00111', '10101', '10111']
> python3 test.py
???
['000', '001', '010', '011', '100', '101', '110', '111']
> python3 test.py
?
['0', '1']
> python3 test.py
[]
>
Upvotes: 2
Reputation: 114068
import itertools
import re
inp = "?01?1"
for combination in itertools.product("01", repeat=inp.count("?")):
i_combination = iter(combination)
print(re.sub("\?",lambda m: next(i_combination),inp))
this just uses the builtin itertools.product
to create all possible strings of "01" of length N(however many question-marks there are in the string)
then it converts each one of those into an iterator where each item is consumed as soon as it is seen,
then we use re.sub
to substitute our products into our original strings, in place of our question-marks
here it is in a repl https://repl.it/@JoranBeasley/AssuredAncientOpengroup
I see in a comment here you dont want to use builtins ... so nevermind then i guess
if you do not want to use builtin itertools.product .. .simply write your own
def my_product(s,r):
if r < 1:
yield ""
for i in range(r):
for c in s:
for partial in my_product(s,r-1):
yield c+partial
same with built in iter
def my_iter(s):
for c in s:
yield c
and lastly we need to write our own custom subber
def my_substitute(s,replacement):
iter_replacement = my_iter(replacement)
while s.count("?"):
s = s.replace("?",next(iter_replacement))
return s
now we tie it all together in the same way
inp = "?01?1"
for combination in my_product("01", inp.count("?")):
print(my_substitute(inp,combination))
Upvotes: 2
Reputation: 912
a list is a mutable type, that means that you only have one list on which all modifications are made. This causes your first call fill(inp)
to also fill the remaining '?' in inp
, thus only giving you one result with the second option for the first ? (first ?=1: two results, first ?=0: one result because the last result of the first ? is still saved in the list)
To resolve this problem, use list.copy()
. This will pass a copy of the list to fill()
and thus cause the original list to be left as it is.
Your complete code with .copy()
and other minor modifications:
anslist = []
def fill(inp):
if inp.count("?") == 0:
print(inp, "WAS ADDED")
anslist.append(inp)
return
for a in range(len(inp)): # range(0, x) is equivalent to range(x); try to limit global variables
if inp[a] == "?":
inp[a] = 1
fill(inp.copy()) # list is mutable
inp[a] = 0
fill(inp.copy()) # see above
return
user_input = list(input())
fill(user_input)
print(anslist)
Upvotes: 2
Reputation: 3612
Here's example solution without using builtin tools. Here we use recursion, when we occur '?' during iterating over our input we replace it with '0' and '1' and add result of fill()
of what's after current index.
userInput = input()
def fill(inp):
ret = []
for idx, i in enumerate(inp):
if i == '?':
for rest in fill(inp[idx+1:]):
ret.append(inp[:idx] + '0' + rest)
ret.append(inp[:idx] + '1' + rest)
break
else:
return [inp]
return ret
print(fill(userInput))
Output
?01?1 -> ['00101', '10101', '00111', '10111']
??? -> ['000', '100', '010', '110', '001', '101', '011', '111']
Upvotes: 2
Reputation: 8345
Sample python code using itertools.product (you can use an equivalent implementation but this is fine)
from itertools import product
def generate_combinations(inp):
count = 0
for a in range(0, len(inp)):
if inp[a] == "?": count += 1
combinations = []
for comb in product(range(2), repeat=count):
pos = 0
cinp = inp[:]
for a in range(len(cinp)):
if cinp[a] == '?':
cinp[a] = str(comb[pos])
pos += 1
combinations.append(cinp)
return combinations
example usage:
print(generate_combinations('?01?1'))
Upvotes: 1