in reply to Re: Spreading out the elements
in thread Spreading out the elements

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?

Replies are listed 'Best First'.
Re^3: Spreading out the elements
by dsheroh (Monsignor) on Jul 05, 2007 at 17:05 UTC
    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