1

I am trying to permutate a string of 0s and 1s of an arbitrary length. I've seen a lot of answers on this topic that do it so that the outcome for a string of length n will be like this for n=3.

000
001
010
011
100
101
110
111

But this is not what I need!

I need it to be like this for length 3:

000
100
010
001
110
101
011
111

For length 4 this would be:

0000
1000
0100
0010
0001
1100
1010
1001
0110
0101
0011
1110
1101
1011
0111
1111

For length 5 it would be:

00000
10000
01000
00100
00010
00001
11000
10100
10010
10001
01100
01010
01001
00110
00101
00011
11100
11010
11001
10110
10101
10011
01110
01101
01011
00111
11110
11101
11011
10111
01111
11111

Etc..

I just can't figure out an algorithm for this, can anyone help me?

Edit: I got pop up suggesting that I could find the answer elsewhere on this site. I am new here so I might not understand correctly but the only overlap I saw in the two questions was the word permutation.

Perm. Questiin
  • 429
  • 2
  • 9
  • 21

1 Answers1

1

This works for me. It does, however, not produce the elements in order but rather first produces them and then sorts them.

n = 5
i = np.array(np.indices(n * (2,))).reshape(n, -1)
i[:, np.argsort(i.sum(0)[::-1], kind='mergesort')].T[::-1]

It sorts the binary words by the sum of their digits, using a stable sort, i.e. one that in case of a tie preserves the original order.

A solution that generates the words in order can be constructed with itertools

itertools.chain((n*(0,),), (l[0] * (0,) + sum(((1,) + (i-j-1) * (0,) for i, j in zip(l[1:], l[:-1])), ()) + (1,) + (n-l[-1]-1)*(0,) for k in range(1,n+1) for l in itertools.combinations(range(n), k)))

This loops over the number of ones k (k = 0 is special cased and prepended using itertools.chain). For each k it uses itertools.combinations to create all k element subsets l of the set `{0, 1, ..., n-1} and translates each subset to a binary word. This translation works by putting a one for each element of l and calculating how many zeros have to go in between. Leading and trailing zeros had to be special cased.

Sample output: numpy:

# array([[0, 0, 0, 0, 0], [1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0],
         [0, 0, 0, 1, 0], [0, 0, 0, 0, 1], [1, 1, 0, 0, 0], [1, 0, 1, 0, 0],
         [1, 0, 0, 1, 0], [1, 0, 0, 0, 1], [0, 1, 1, 0, 0], [0, 1, 0, 1, 0],
         [0, 1, 0, 0, 1], [0, 0, 1, 1, 0], [0, 0, 1, 0, 1], [0, 0, 0, 1, 1],
         [1, 1, 1, 0, 0], [1, 1, 0, 1, 0], [1, 1, 0, 0, 1], [1, 0, 1, 1, 0],
         [1, 0, 1, 0, 1], [1, 0, 0, 1, 1], [0, 1, 1, 1, 0], [0, 1, 1, 0, 1],
         [0, 1, 0, 1, 1], [0, 0, 1, 1, 1], [1, 1, 1, 1, 0], [1, 1, 1, 0, 1],
         [1, 1, 0, 1, 1], [1, 0, 1, 1, 1], [0, 1, 1, 1, 1], [1, 1, 1, 1, 1]])

itertools:

list(_)
# [(0, 0, 0, 0, 0), (1, 0, 0, 0, 0), (0, 1, 0, 0, 0), (0, 0, 1, 0, 0), (0, 0, 0, 1, 0), (0, 0, 0, 0, 1),
   (1, 1, 0, 0, 0), (1, 0, 1, 0, 0), (1, 0, 0, 1, 0), (1, 0, 0, 0, 1), (0, 1, 1, 0, 0), (0, 1, 0, 1, 0),
   (0, 1, 0, 0, 1), (0, 0, 1, 1, 0), (0, 0, 1, 0, 1), (0, 0, 0, 1, 1), (1, 1, 1, 0, 0), (1, 1, 0, 1, 0),
   (1, 1, 0, 0, 1), (1, 0, 1, 1, 0), (1, 0, 1, 0, 1), (1, 0, 0, 1, 1), (0, 1, 1, 1, 0), (0, 1, 1, 0, 1),
   (0, 1, 0, 1, 1), (0, 0, 1, 1, 1), (1, 1, 1, 1, 0), (1, 1, 1, 0, 1), (1, 1, 0, 1, 1), (1, 0, 1, 1, 1),
   (0, 1, 1, 1, 1), (1, 1, 1, 1, 1)]
Paul Panzer
  • 51,835
  • 3
  • 54
  • 99
  • Thank you so much! I'm going to try this first thing tomorrow when I've got a computer again :) I'm on my phone now. – Perm. Questiin Mar 16 '17 at 01:17
  • Can you explain your itertools code? I'm trying it for n=40 and for k in range(1,2) This should just give 41 really basic vectors but for some reason it takes forever. Can you help me optimise? – Perm. Questiin Mar 19 '17 at 02:47
  • @Perm.Questiin I just tried it with `n=40, k in range(1, 2)` and takes just an eye blink on my laptop. Did you apply list to the result? I'll see how I can explain the code a bit better. – Paul Panzer Mar 19 '17 at 22:38
  • You're right! I made a mistake and that slowed it down. Thanks anyway :) – Perm. Questiin Mar 21 '17 at 15:18