Subop has asked for the wisdom of the Perl Monks concerning the following question:

Hello monks!

I need to take the @count array and turn it into the following @result array.

@count: 1 3 1 1 1 1 1 2 1 1 3 2

@result: 0 1 1 1 2 3 4 5 6 7 7 8 9 10 10 10 11 11

Each element in @count is the number of times to repeat the number in @result starting at 0. 0 occurs once, 1 occurs 3 times, 2 occurs once, etc. The problem is once I get to double digits I get this result.

@count: 1 3 1 1 1 1 1 2 1 1 3 2

@result: 0 1 1 1 2 3 4 5 6 7 7 8 9 1 0 1 0 1 0 1 1 1 1 <- Wrong!

for (my $i=0; $i <= $#count; $i++) { push(@result, split("", $i x $count[$i])); } print "\@count: @count\n"; print "\@result: @result\n";

I understand why it isn't working, but I've tried everything I can think of to fix it yesterday and today, and still can't find the solution. Any help is appreciated.

Replies are listed 'Best First'.
Re: Problem creating array
by moritz (Cardinal) on Sep 16, 2009 at 14:19 UTC
    If you use a list on the left hand side of the x repetition operator, it generates a list, not a string:
    push(@result, ($i) x $count[$i]);
    Perl 6 - links to (nearly) everything that is Perl 6.

      Man you guys are good. You wouldn't believe the mess of loops I had trying to solve this problem. Thanks for everyone's help!

        Even if you didn't know how to use "x" to do what you want, it's not messy to do it without "x".
        # With "x" for my $i (0..$#count) { push @result, ($i) x $count[$i]; }
        # Without "x" for my $i (0..$#count) { for (1..$count[$i]) { push @result, $i; } }
Re: Problem creating array
by mwah (Hermit) on Sep 16, 2009 at 14:25 UTC
    ... my $p=0; push @result, ($p++)x$_ for @count; ...
Re: Problem creating array
by Unforgiven (Hermit) on Sep 16, 2009 at 14:26 UTC
    I just used a foreach, because the x looked to be related to the problem, and it was the first and simplest thing that came to mind. You could do it shorter and more elegantly, but this works and is probably a little easier to read if you're still learning a bit.
    my @count = (1,3,1,1,1,1,1,2,1,1,3,2); my @result; for (my $i=0; $i <= $#count; $i++) { foreach (1 .. $count[$i]) { push(@result, $i); } } print "\@count: @count\n"; print "\@result: @result\n";
      The shorter, more elegant approach involves the use of the map built-in. You (Subop) don't need it right now, but you should keep  map in mind as you build your Perl skills.
      >perl -wMstrict -le "my @count = (1, 3, 1, 1, 1, 1, 1, 2, 1, 1, 3, 2); my @result = map { ($_) x $count[$_] } 0 .. $#count; print qq{@count}; print qq{@result}; " 1 3 1 1 1 1 1 2 1 1 3 2 0 1 1 1 2 3 4 5 6 7 7 8 9 10 10 10 11 11

        A slightly simpler map at the cost of declaring another scalar.

        $ perl -Mstrict -wle ' > my @count = ( 1, 3, 1, 1, 1, 1, 1, 2, 1, 1, 3, 2 ); > my $idx; > my @result = map { ( $idx ++ ) x $_ } @count; > print qq{@count}; > print qq{@result};' 1 3 1 1 1 1 1 2 1 1 3 2 0 1 1 1 2 3 4 5 6 7 7 8 9 10 10 10 11 11 $

        I hope this is of interest.

        Cheers,

        JohnGG

Re: Problem creating array
by biohisham (Priest) on Sep 16, 2009 at 18:01 UTC
    I've learnt a lot reading this post. What struck me was how you used split("",$i x $count[$i]) inside the loop. Here what you're pushing to the array as an element is the outcome of the split operation, in the split you used here, the "" gives unexpected or unwanted results if it is not precise to you what you are intending to do so. At some times it could become better that you assign the outcome to a variable first before pushing it to an array or manipulating it other ways.

    have a happy programming and best of luck.


    Excellence is an Endeavor of Persistence. Chance Favors a Prepared Mind.