14

I have two arrays:

@arr1 = ( 1, 0, 0, 0, 1 );
@arr2 = ( 1, 1, 0, 1, 1 );

I want to sum items of both arrays to get new one like

( 2, 1, 0, 1, 2 );

Can I do it without looping through arrays?

5
  • Are the numbers always 0 and 1? If so you could treat that as an integer and just add two integers together to give you a third integer with the same digits as that array. Commented Dec 8, 2009 at 10:16
  • Obviously that also presumes that the number of digits is small. Commented Dec 8, 2009 at 10:16
  • It's OK. I have only 0 and 1. Commented Dec 8, 2009 at 10:27
  • 2
    Why don't you want to loop over them? Do you have some aversion to solving the problem and moving on in life? :) Commented Dec 9, 2009 at 1:04
  • If the arrays are massive and speed is an issue consider PDL perlmonks.org/?node_id=598007 Commented May 25, 2014 at 5:37

9 Answers 9

31

for Perl 5:

use List::MoreUtils 'pairwise';
@sum = pairwise { $a + $b } @arr1, @arr2;
Sign up to request clarification or add additional context in comments.

4 Comments

@melco-man: I thought you wanted the result to be in a reference to an array, otherwise square brackets are not needed
@melco-man: don't declare my($a,$b) - they are special variables here and 'pairwise' takes care of $a and $b localization for you
This does actually loop through both arrays, it's just hidden inside of pairwise.
Seems slower then looping through one array and adding one element to the other too
8

If you're using Perl 6:

@a = (1 0 0 0 1) <<+>> (1 1 0 1 1)  #NB: the arrays need to be the same size

The Perl 6 Advent Calendar has more examples.

3 Comments

See @catwalk for a Perl 5 implementation.
is <<+>> the hovercraft operator?
@Ether, I think it may be the UFO operator.
8

Fundamentally, no, you can't do it without "looping through arrays" because you need to access every element of both arrays in order to sum them. Both the answers so far just hide the looping under a layer of abstraction but it's still there.

If you're concerned about looping over very large arrays, it's probably best to consider other ways of keeping the sum up-to-date as you go.

Comments

7

what's wrong with looping over arrays? that's the fundamentals.

@arr1 = ( 1, 0, 0, 0, 1 );
@arr2 = ( 1, 1, 0, 1, 1 );
for ($i=0;$i<scalar @arr1;$i++){
    print $arr[$i] + $arr2[$i] ."\n";
}

1 Comment

i know exactly what i am doing. I don't like to think complicated, that's all.
6

You've seen a C style for loop, and pairwise. Here's an idiomatic Perl for loop and map:

my @arr1 = ( 1, 0, 0, 0, 1 );
my @arr2 = ( 1, 1, 0, 1, 1 );

my @for_loop;
for my $i ( 0..$#arr1 ) { 
    push @for_loop, $arr1[$i] + $arr2[$i];
}

my @map_array = map { $arr1[$_] + $arr2[$_] } 0..$#arr1;

I like map and pairwise best. I'm not sure that I have a preference between those two options. pairwise handles some boring details of plumbing for you, but it is not a built-in like map. On the other hand, the map solution is very idiomatic, and may be opaque to a part-time perler.

So, no real wins for either approach. IMO, both pairwise and map are good.

Comments

2

From http://www.perlmonks.org/?node_id=122393

@a = qw(1 2 3 4);
@b = qw(1 2 3 4);
@c = (); 

@c = map { $a[$_] + $b[$_] } ( 0 .. (@a > @b ? $#a : $#b) );

Or:

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

Or:

$c[$_] = $a[$_] + $b[$_] for 0 .. (@a > @b ? $#a : $#b);

Or (in Perl 6):

@c = @a ^+ @b

Comments

1

If you're really afraid of looping, then you can binary chop the arrays, sum the pairs, then recursively reassemble the resulting array. No looping there, and as a bonus you get to learn how part of the fast-fourier transform derivation works.

1 Comment

Use recursion instead of looping - great idea!
0

To avoid (explicit) looping, here is a solution that uses recursion "instead":

#!/usr/bin/perl

use v5.20;

my @arr1 = ( 1, 0, 0, 0, 1 );
my @arr2 = ( 1, 1, 0, 1, 1 );

my @result=non_looping_pairwise_sum([ @arr1 ], [ @arr2 ]); # pass in copies, so the originals are not modified
say "@result";

sub non_looping_pairwise_sum { # only handles lists that have the same length
    my ($a1, $a2)=@_;

    return () if (scalar(@$a1)==0 and scalar(@$a2)==0);

    my $e1=shift @$a1;
    my $e2=shift @$a2;

    return ($e1+$e2, non_looping_pairwise_sum($a1, $a2));
}

Output:

2 1 0 1 2

Note that use v5.20 means you don't have to write use strict; use warnings, I think.

Apologies/kudos to @parm for the idea.

Comments

0

I'm not sure what you plan to do with the sum once you have it, but you plan to do more vector-y type stuff, then Math::Matrix might be a good fit.

use Math::Matrix;

my $foo = Math::Matrix->new([ 1, 0, 0, 0, 1 ]);
my $bar = Math::Matrix->new([ 1, 1, 0, 1, 1 ]);
my $sum = $foo->add($bar);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.