in reply to Spreading out the elements

Since you want a neat and fair distribution, I'd try a recursive solution. With recursion it's easy to produce symmetric patterns. Something like:
interleave() choose a "pretty layout" method, e.g. More than one A? Y: remove two 'A' from pool return 'A' . interleave() . 'A' More than one B? Y: remove two 'B' from pool return 'B' . interleave() . 'B' one 'A'? Y: remove 'A' from pool return 'A' remove 'B' from pool return 'B'

...roboticus

Replies are listed 'Best First'.
Re^2: Spreading out the elements
by oko1 (Deacon) on Jul 04, 2007 at 14:32 UTC
    I'm sorry, I seem to be missing your point. Are you saying something like this?
    sub recurse { if (grep /A/, @a > 1){ my @c = splice @a, 0, 2; splice @c, 1, 0, (@a +, @b); } if (grep /B/, @b > 1){ my @c = splice @b, 0, 2; splice @c, 1, 0, (@a +, @b); } if (grep /A/, @a == 1){ shift @a; } if (grep /B/, @b == 1){ shift @b; } }
    If so, how would you call it and how would you terminate it?
      Here's a simple implementation of the suggested recursive algorithm. Note that you don't really need the arrays, so I'm just using a count of how many of each letter are left:
      #!/usr/bin/perl use strict; print_interleave(1,1); print_interleave(2,1); print_interleave(1,2); print_interleave(2,2); print_interleave(3,3); print_interleave(4,14); print_interleave(7,4); sub print_interleave { my ($total_a, $total_b) = @_; print '(', $total_a, ', ', $total_b, ")\t"; print interleave($total_a, $total_b), "\n"; } sub interleave { my ($remaining_a, $remaining_b) = @_; if ($remaining_a > 1) { return 'A' . interleave($remaining_a - 2, $remaining_b) . 'A'; } elsif ($remaining_b > 1) { return 'B' . interleave($remaining_a, $remaining_b - 2) . 'B'; } elsif ($remaining_a == 1) { return 'A'; } elsif ($remaining_b == 1) { return 'B'; } else { return ''; # Just for completeness } }
      Unfortunately, it doesn't produce the correct results:
      (1, 1) A (2, 1) ABA (1, 2) BAB (2, 2) ABBA (3, 3) ABABA (4, 14) AABBBBBBBBBBBBBBAA (7, 4) AAABBABBAAA
      As for how to terminate it, every time interleave() calls itself, it reduces either $remaining_a or $remaining_b. One of them will eventually reach 0 and terminate that branch of the recursion. Since nothing in interleave() ever increases them, all branches will terminate.

      UPDATE: Replacing the above interleave() with this interleave2()

      sub interleave2 { my ($remaining_a, $remaining_b) = @_; if ($remaining_a > 1 && $remaining_b) { my $b_range = int($remaining_b/($remaining_a - 1)); return 'A' . 'B' x $b_range . interleave2($remaining_a - 1, $remai +ning_b - $b_range); } elsif ($remaining_a) { return 'A' . interleave2($remaining_a - 1, $remaining_b); } elsif ($remaining_b) { return 'B' . interleave2($remaining_a, $remaining_b - 1); } else { return ''; # Just for completeness } }
      appears to produce correct results:
      (1, 1) AB (2, 1) ABA (1, 2) ABB (2, 2) ABBA (3, 3) ABABBA (4, 14) ABBBBABBBBBABBBBBA (7, 4) AAABABABABA

        esper:

        ++ Nice implementation, test & improvement!

        I was actually not proposing my algorithm as being a correct one or not, just suggesting a mode of attack. (I like recursion for tasks like this.) But judging from your results, I wasn't terribly far off.

        ...roboticus