Going through all binary combinations with some numbers as “?”

末鹿安然 提交于 2019-12-24 01:25:15

问题


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.


回答1:


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)



回答2:


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



回答3:


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



回答4:


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

[]
>



回答5:


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


来源:https://stackoverflow.com/questions/54065561/going-through-all-binary-combinations-with-some-numbers-as

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!