http://www.perlmonks.org?node_id=1026278

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

Dear community, I would like to do with an arry like e.g.
@array = qw (0 1 3 2 ) ;
the following:
I would like to calculate the sums of all the items, but with interim results.
I would like to get another array consisting of the all these interim results, in this special case:
@newarray = qw ( 0 1 4 6 ); #0+1, 1+3, 3+2
How can I do this?
I thank You for Your patience, it's one of my very first steps I do with perl-

Replies are listed 'Best First'.
Re: adding items, but with interim results
by moritz (Cardinal) on Mar 30, 2013 at 16:27 UTC

    I know you probably want a solution in Perl 5, but here is one in Perl 6, because it hapepns to be very short:

    $ perl6 -e 'say [\+] 0, 1, 3, 2' 0 1 4 6

    Enclosing an infix operator like + with square brackets applies it to a list, as if you had written  0 + 1 + 4 + 6. The [\infix] for also returns the intermediate results.

    Mnemonic: the [\ has the shape of a triangle, just like the list of expressions that is generated from it:

    0 0 + 1 0 + 1 + 4 0 + 1 + 4 + 6
Re: adding items, but with interim results
by toolic (Bishop) on Mar 30, 2013 at 15:06 UTC
    3+2=6??
    use warnings; use strict; my @array = qw (0 1 3 2 ) ; my @newarray = $array[0]; for my $i (1 .. $#array) { push @newarray, $array[$i-1] + $array[$i]; } print "@newarray\n"; __END__ 0 1 4 5

    Or, maybe your spec is ambiguous:

    my @array = qw (0 1 3 2); my @newarray = $array[0]; my $sum = $array[0]; for my $i (1 .. $#array) { $sum += $array[$i]; push @newarray, $sum; } print "@newarray\n"; __END__ 0 1 4 6
Re: adding items, but with interim results
by davido (Cardinal) on Mar 30, 2013 at 15:45 UTC

    You ought to let us know what you've tried and where you're stuck. That way when we help you past the part you're stuck with, you can still turn it in as your own work, and you will have learned something along the way. Just asking for a solution will get you "our work", and leave you with a learning deficit that will need to be repaid before you comprehend the next assignment.

    The most straightforward ways will probably use foreach or map, and will probably iterate over the indices of the array. But just for fun, here's a solution that you would never turn in, or put into production:

    use strict; use warnings; my @array = qw( 0 1 3 2 3 4 2 ); my @sums; for( "@array" ) { push @sums, $1 + $2 while m/(\d+)\s(?=(\d+))/g; } { local $" = ', '; print "[ @sums ]\n"; }

    Dave

Re: adding items, but with interim results
by kcott (Archbishop) on Mar 30, 2013 at 15:44 UTC

    G'day kontrapunktstefan,

    Welcome to the monastery.

    Your description is ambiguous. I suspect #0+1, 1+3, 3+2 should be #0+0, 0+1, 1+3, 4+2. If this is actually what you want, there are many ways to code it; here's one:

    $ perl -Mstrict -Mwarnings -E ' my @x = (0,1,3,2); my @y = map { state $z = 0; $z += $_ } @x; say "@y"; ' 0 1 4 6

    -- Ken

      my @y = map { state $z = 0; $z += $_ } @x;

      The use of the state scalar variable  $z in the map BLOCK in this statement is neat, but it presents a stumbling block to which it is perhaps unwise to expose a novice lest he or she be precipitated, however inadvertently, from the True Path.

      A state variable, of course, maintains its state from one access to the next regardless of whether or not the lexical scope enclosing the variable is exited and re-entered. This is fine if the statement containing the variable is executed once and only once in the execution of a program; if it is not, the results may be surprising. (In the example below the source array  @w is repeatedly dumped just to show that it never changes.)

      >perl -wMstrict -MData::Dump -lE "sub summer { return map { state $z = 0; $z += $_; } @_; } ;; my @w = qw(0 1 3 2); my @x = summer(@w); my @y; @y = map { state $z = 0; $z += $_; } @w for 1 .. 3; my @z = map { state $z = 0; $z += $_; } @w; ;; dd \@w; dd \@x; dd \@y; dd \@z; ;; @x = summer(@w); @y = map { state $z = 0; $z += $_; } @w for 1 .. 3; @z = map { state $z = 0; $z += $_; } @w; ;; print '----------'; dd \@w; dd \@x; dd \@y; dd \@z; ;; print '----------'; dd \@w; " [0, 1, 3, 2] [0, 1, 4, 6] [12, 13, 16, 18] [0, 1, 4, 6] ---------- [0, 1, 3, 2] [6, 7, 10, 12] [12, 13, 16, 18] [0, 1, 4, 6] ---------- [0, 1, 3, 2]
        > but it presents a stumbling block to which it is perhaps unwise to expose a novice

        I second this!

        Especially because state has some implementation issues besides needing to be activated with use feature.

        a simple my $z outside the map has the same effect and is backwards compatible.

        DB<104> @x=1..4 => (1, 2, 3, 4) DB<105> use feature state; my @y = map { state $z = 0; $z += $_ } @x +; => (1, 3, 6, 10) DB<106> my $z; my @y = map { $z += $_ } @x; => (1, 3, 6, 10)

        and if the scope of $z is of importance, use blocks to limit it.

        DB<107> my @y; { my $z; @y = map { $z += $_ } @x; } => (1, 3, 6, 10) DB<109> my @y = do { my $z; map { $z += $_ } @x } => (1, 3, 6, 10)

        Cheers Rolf

        ( addicted to the Perl Programming Language)

        IMHO it's not state which is buggy but rather map.

        see this

        DB<168> sub tst (&@) { my $cr=shift; print $cr->($_)," " for @_ } DB<169> use feature 'state'; tst {state $i++} 1..3 for 1..3 => "" 0 1 2 0 1 2 0 1 2

        The blocks of map and grep are no anonymous subroutines as Tobyink pointed out recently.

        IMHO thats why scoping fails in your tests.

        DB<173> use feature 'state'; map {state $i++; print "$i "} 1..3 for +1..3 => "" 1 2 3 4 5 6 7 8 9

        (at least with 5.10)

        udate

        also while conditions

        DB<195> use feature 'state'; for (1..3) { $y=0;while (++(my $x)) { p +rint " $x .";last if $y++>3 } } => "" 1 . 1 . 1 . 1 . 1 . 1 . 1 . 1 . 1 . 1 . 1 . 1 . 1 . 1 . 1 . DB<196> use feature 'state'; for (1..3) { $y=0;while (++(state $x)) +{ print " $x .";last if $y++>3 } } => "" 1 . 2 . 3 . 4 . 5 . 6 . 7 . 8 . 9 . 10 . 11 . 12 . 13 . 14 . 15 .

        Cheers Rolf

        ( addicted to the Perl Programming Language)

Re: adding items, but with interim results
by LanX (Saint) on Mar 30, 2013 at 17:20 UTC
    please clarify your question!

    > I would like to calculate the sums of all the items, but with interim results.

    contradicts

    > @newarray = qw ( 0 1 4 6 ); #0+1, 1+3, 3+2

    where you are calculating only the sum of neighboring pairs, not all items (see 3+2)!

    two different tasks, you got quite good answers for both.

    Cheers Rolf

    ( addicted to the Perl Programming Language)

Re: adding items, but with interim results
by zwon (Abbot) on Mar 30, 2013 at 15:05 UTC

    That's fairly trivial and can be done using map. I don't want to spoil you a joy of discovery, so not giving the answer.

      > That's fairly trivial and can be done using map. I don't want to spoil you a joy of discovery, so not giving the answer.

      Agreed!

      (Hint  $sum+=$_ ;-)

      Cheers Rolf

      ( addicted to the Perl Programming Language)

Re: adding items, but with interim results
by jms53 (Monk) on Mar 30, 2013 at 15:12 UTC
    use strict; use warnings; my @array = qw ( 0 1 3 2 ); my @newarray; for (@array) { push @newarray, $newaaray[-1]+$_; #will probably bug for $array[0] }
    J -