0

I got the following problem. Given a word (a binary one) I want to generate all the combinations with length n, and the given word can not be a prefix of any of the combinations.

For instance, with n = 3 and the word is 00 I would like to generate:

010
011
100
101
110
111

Is there any pythonic way to do this?

Edit: Sorry, I am trying modifications of this standard pseudo-code

combinations:
if depth = 0 return result
for i in start..size
    out+=combinations(depth-1, i+1, result)
return out

I can't figure out how to add the restriction of not starting by the given word. By "pythonic" I mean with something like comprehension lists, or a beautiful one-liner :D

Norhther
  • 545
  • 3
  • 15
  • 35
  • 3
    Sure there is, but what have you tried so far ? – MooingRawr Feb 26 '18 at 16:36
  • 2
    What do you mean "a pythonic way"? It's quite a specific (if simple) algorithm, I don't think there can be any super-smart trick to do it in one or two lines. Have you tried some code that is not working, that you want to improve or are you asking how to solve the problem in general? – jdehesa Feb 26 '18 at 16:36
  • 1
    It can definitely be done in one line, but I wouldn't exactly call it Pythonic! – ACascarino Feb 26 '18 at 16:49
  • Your pseudocode is difficult to understand, since it doesn't show where any of the variables come from except `i`. It also doesn't seem to modify `result` or `out`. But at a guess, you could check whether `result` or `out` starts with `word` before calling down deeper. – Matthias Fripp Feb 26 '18 at 18:45

1 Answers1

0

You can do all the work in a one-liner, but it takes a bit of setup. This takes advantage of the fact that you basically want all the binary numbers within a range of 0 to 2**n, except if their leftmost bits represent a particular binary number. Note that in general you will be keeping most of the numbers in the range (all but 1/2**len(word)), so it's reasonably efficient just to generate all the numbers and then filter out the ones you don't want.

word = '00'
word_int = int(word, base=2)
m = len(word)
n = 3
results = ['{0:b}'.format(num).zfill(n) for num in range(2**n) if num >> (n-m) != word_int]
print('\n'.join(results))
# 010
# 011
# 100
# 101
# 110
# 111

You can eliminate some of the setup, but the one-liner gets harder to read:

word = '00'
n = 3
[
    num 
    for num in ('{0:b}'.format(p).zfill(n) for p in range(2**n)) 
    if not num.startswith(word)
]

Or you can use itertools.product

word = '00'
n = 3
[
    num 
    for num in (''.join(p) for p in itertools.product('01', repeat=n)) 
    if not num.startswith(word)
]
Matthias Fripp
  • 17,670
  • 5
  • 28
  • 45