Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Re: Summing the elements of multiple arrays into a new array

by Sidhekin (Priest)
on Oct 31, 2001 at 23:18 UTC ( [id://122414]=note: print w/replies, xml ) Need Help??


in reply to Summing the elements of multiple arrays into a new array

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)},"

Replies are listed 'Best First'.
Re: Re: Summing the elements of multiple arrays into a new array
by TheDamian (Vicar) on Nov 01, 2001 at 12:47 UTC
      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)},"

        For my next hope-to-see, that reduce will DWIM with lists

        I don't think any of the syntaxes you suggested will be the way to do this, but it might be that reduce will honour the parameter contexts specified by its reduction block, so this would work:

        @foobar = reduce {[@^a ^+ @^b]} @foo, @bar, @baz, @etc;

        How? Well, the @^a and @^b make the reduction block a curried subroutine, whose parameter list consists of two unflattened arrays. That is:

        {[@^a ^+ @^b]}
        is shorthand for:
        sub (@a, @b) { return [@a ^+ @b] }
        (modulo the currying (which isn't used here (so forget I mentioned it))).

        With that parameter list on its reduction block, reduce would expect arrays instead of scalars as its remaining arguments.

        Note that the square brackets are critical here, since reduce always applies the reduction in scalar context, but we need to get back something that can be treated like an array in the next reduction (i.e. an array reference).

        That is: the result of the first reduction step has to be a scalar, but that result -- when it becomes the first argument to the reduction block in the second step of the reduction -- has to be an array. Perl 6's auto-intra-conversion of arrays and array refs makes that possible.

        Having reduce and other list ops honour their block's parameter list would be very cool in other ways too:

        # sum of maximal values... $maxsum = reduce { $^a + max(@^b) } 0, @foo, @bar, @etc;

        In this example the reduction block has two parameters: a scalar and an unflattened array. So it sucks corresponding elements from the argument list (i.e. 0 and @foo), finds the maximum value in @foo, and adds it to the partial sum. The result becomes the first argument of the next reduction step, which then grabs @bar for its second argument, finds @bar's maximum and adds it in. That result becomes the first argument to the third reduction, which grabs @etc, and adds its maximum as well. Having exhausted all its arguments, reduce returns the final reduction result, which turns out to be the sum of all maxima.

        Pushing the envelope a little, we could also write:

        # grep out hash entries whose key *or* value is 'moo'... %cow = map { any($^key,$^val) eq 'moo' ?? $^key => $^val :: () } % +animals;

        Here, the mapping block is equivalent to:

        sub ($key, $val) { ... }
        So each mapping step would pull two scalar arguments off the map's argument list. If either is 'moo', the block returns the pair; otherwise it returns an empty list (which is flattened out of existence in the resultant list). The outcome is that the %cow hash is assigned a list of pairs, which become its entries.

        Where to the scalar keys and values come from? They're flattened out of the %animals hash by the scalar contexts imposed by the two scalar arguments of the reduction block (!)

        BTW, that map { $test ? $result : () } @data construct is a trick you can use in Perl 5 too. It's the infamous "grepping map" (i.e. a floor wax and a dessert topping).

        Update: Fixed the missing second colon on the ternary operator in the last example. Thanks blakem!

        Unless there is one flattening and one non-flattening reduce...

        There won't be.

        that would mean that to apply reduce to the flattened list, you would need to explicitly flatten it, right?

        Right.

Re: Re: Summing the elements of multiple arrays into a new array
by kwoff (Friar) on Nov 01, 2001 at 05:55 UTC
    Hmm, I think in perl6 it's simply
    @foobar = @foo ^+ @bar
    The '^' makes '+' a "vector" operator.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (6)
As of 2024-04-19 07:44 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found