Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Summing the elements of multiple arrays into a new array

by djw (Vicar)
on Oct 31, 2001 at 22:38 UTC ( [id://122393]=perlquestion: print w/replies, xml ) Need Help??

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

I am adding elements of multiple arrays together and creating a new array with the sum. I was curious to know if there was a perlish one-liner type way of doing this. Here is how I'd do it using a loop:
# using a loop @foo = qw(1 2 3 4); @bar = qw(1 2 3 4); for ($i = 0; $i < 4; $i++) { $foobar[$i] = $foo[$i] + $bar[$i]; } # @foobar is now (2 4 6 8).

I have no problem doing it that way, but I was just curious. One day I may need to do this to more than two 4 element arrays and I won't want to type all that =)

djw

Replies are listed 'Best First'.
Re: Summing the elements of multiple arrays into a new array
by Masem (Monsignor) on Oct 31, 2001 at 22:42 UTC
    @foobar = map { $foo[$_] + $bar[$_] } ( 0..(@foo > @bar ? $#foo : $#ba +r ) );

    -----------------------------------------------------
    Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain
    "I can see my house from here!"
    It's not what you know, but knowing how to find it if you don't know that's important

Re: Summing the elements of multiple arrays into a new array
by larsen (Parson) on Oct 31, 2001 at 22:47 UTC
    My two cents...
    my $max = ($#foo > $#bar) ? $#foo : $#bar; # or we can assert they have the same size? @foobar = map { $foo[$_] + $bar[$_] } (0..$max);
    Or you could wait Perl 6 :)
Re: Summing the elements of multiple arrays into a new array
by Sidhekin (Priest) on Oct 31, 2001 at 23:18 UTC

    Okay, we need a bit of sillyness here ...

    use 6; # require perl v6 use List::Util qw/reduce/; @foobar = @{reduce{[@$a ^+ @$b]}\(@foo, @bar, @baz, @etc)};

    Note: Untested :-)

    Update: Oops, pushed the wrong button. (Note to self: In the future, type the non-silly version first ...)

    What you want is something that is easily extendable -- "more than two 4 element arrays" suggests that to me, at least. So, work with lists:

    use List::Util qw/reduce/; @foobar = @{reduce{[map $a->[$_]+$b->[$_], 0..@$a>@$b?$#$a:$#$b]} \(@foo, @bar, @baz, @etc};

    Unfortunately, this is also untested, as I am at work with no List::Util installed ... also unfortunately, this is still a lot of typing, and it creates a lot of anonymous arrays, so don't use it mindlessly :-\

    The Sidhekin
    print "Just another Perl ${\(trickster and hacker)},"

        use 6; # require perl v6
        use List::Util qw/reduce/;
      
        @foobar = @{reduce{@$a ^+ @$b}\(@foo, @bar, @baz, @etc)};
      

      reduce will almost certainly be a built-in in Perl 6, so you won't need to use List::Util.

      That hideously lovely third line certainly would do the job in Perl 6 (well done!), but was it really necessary to be so cruel to the mere mortals who'll have to maintain that code???

      kwoff is perfectly correct -- in Perl 6 you'll just need:

      	@foobar = @foo ^+ @bar ^+ @baz ^+ @etc;
      
      or possibly even:
      	@foobar = ^sum(@foo,@bar,@baz,@etc);
      
      BTW, all of the above code has been tested. ;-)

        That hideously lovely third line certainly would do the job in Perl 6 (well done!), but was it really necessary to be so cruel to the mere mortals who'll have to maintain that code???

        Of course not -- that was just sillyness :-)

        What I really wanted was to show off reduce. And so, I am very happy to hear that reduce will (almost certainly) be a built-in in Perl 6. For my next hope-to-see, that reduce will DWIM with lists (still silly, since "^+" is as easy as ",", but in this context, that is just an example, okay):

        # I hope this works: @foobar = reduce {@a ^+ @b} @foo, @bar, @baz, @etc; # ... or this: @foobar = reduce {@$a ^+ @$b} @foo, @bar, @baz, @etc; # ... or possibly this: @foobar = reduce {$a ^+ $b} @foo, @bar, @baz, @etc;

        Unless there is one flattening and one non-flattening reduce (which sounds like a waste), that would mean that to apply reduce to the flattened list, you would need to explicitly flatten it, right?

        @foobar = reduce {$a + $b} *(@foo, @bar, $baz, $etc);

        Looks weird, but I could live with it :-)
        {... daydreams of Perl 6 ...}

        The Sidhekin
        print "Just another Perl ${\(trickster and hacker)},"

      Hmm, I think in perl6 it's simply
      @foobar = @foo ^+ @bar
      The '^' makes '+' a "vector" operator.
Re: Summing the elements of multiple arrays into a new array
by andye (Curate) on Oct 31, 2001 at 22:52 UTC
    My USD .02 :
    @a=qw(1 2 3 4); @b=qw(1 2 3 4); @c=(); $c[@c] = $a[@c] + $b[@c] while defined $a[@c] and defined $b[@c]; print "@c \n";
    It's not very readable though - frankly, I'd stick with the one you're already using!

    andy.

      That is a pretty cool looking solution there andye, but shouldn't you use or instead of and, to account for cases where one array may have greater length than the other, as the other responses do? I can't help but point out that as written, your solution only works in the special case where both arrays have the same number of elements...

        mull, you're absolutely right. The reason I didn't was that I assumed the compiler would squeal about undefined values if I tried to add a value that didn't exist. But of course it doesn't - what with this being Perl, and all. ;)

        So

        $c[@c] = $a[@c] + $b[@c] while defined $a[@c] or defined $b[@c];

        andy.

Re: Summing the elements of multiple arrays into a new array
by jeroenes (Priest) on Oct 31, 2001 at 23:19 UTC
    You could peak at PDL
Re: Summing the elements of multiple arrays into a new array
by blakem (Monsignor) on Oct 31, 2001 at 23:40 UTC
    If you don't mind destroying @foo and @bar in the process....
    push @foobar, shift(@foo) + shift(@bar) while @foo || @bar;
    (you could use temporary copies of @foo and @bar to avoid losing them in the calculation)

    -Blake

Re: Summing the elements of multiple arrays into a new array
by CharlesClarkson (Curate) on Nov 01, 2001 at 03:59 UTC

    You could just flatten out the loop you have:

    my @foo = my @bar = qw(1 2 3 4); my @foobar; $foobar[$_] = $foo[$_] + $bar[$_] for 0 .. $#foo;

    Now it will handle any two equally sized arrays and is fairly readable.


    HTH,
    Charles K. Clarkson
Re: Summing the elements of multiple arrays into a new array
by Aighearach (Initiate) on Nov 01, 2001 at 01:12 UTC
    without measuring lengths or worring about that...
    (use a #12 hook for the void map...)
    map { $sum += $_ } @foo, @bar;
    or if you're not fi^H^Hgolfing:
    use strict; my $sum = 0; my @foo = ( 2,4,6,8 ); my @bar = ( 200,400,600,800 ); foreach (@foo,@bar) { $sum += $_; }

    --
    Snazzy tagline here

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://122393]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (4)
As of 2024-04-25 19:38 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found