Perl Monk, Perl Meditation PerlMonks

### Array looping

by Nansh (Acolyte)
 on Apr 12, 2017 at 07:22 UTC Need Help??

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

I am not able to do looping with two arrays simultaneously

I need to match the each elements from the below array

This should be done without using any modules

Eg: Array 1: A T C G T C G A G C G

Array 2: A C G T C C T G T C G

```my (\$array1ref, \$array2ref) = @_;

my @array1 = @\$array1ref;
my @array2= @\$array2ref;
my \$count = 0;
foreach my \$element (@array1) {
foreach my \$element2 (@array2) {
if (\$element eq \$element2) {
\$count++;
}else { ???????????

}

Thank you

Replies are listed 'Best First'.
Re: Array looping
by johngg (Canon) on Apr 12, 2017 at 10:12 UTC

Rather than walking the arrays, use join and xor the joined strings, counting nuls with tr.

```johngg@shiraz:~/perl/Monks > perl -Mstrict -Mwarnings -E '
my @arr1  = qw{ A T C G T C G A G C G };
my @arr2  = qw{ A C G T C C T G T C G };
my \$count =
( ( join q{}, @arr1 ) ^ ( join q{}, @arr2 ) ) =~ tr{\0}{};
say \$count;'
4

I hope this is of interest.

Cheers,

JohnGG

That's interesting. I hardly ever think of using the string xor operator. Surely your solution can be golfed, though...

```\$ perl -alpE '\$_=(\$F[0]^\$F[1])=~tr{\0}{}'
ATCGTCGAGCG ACGTCCTGTCG
4
^D

Well, since the OP's post started with arrays rather than strings your golf is cheating slightly ;-)

However, if the problem comes from the real world I think the odds are better than even that the OP started with strings and split them into arrays in order to do the comparison. In that scenario your golf is fine, though anything other than "snippet" dna strings are unlikely to fit on the command line!

Cheers,

JohnGG

32 strokes:

```\$ perl -pale '\$_^=\$F[1];\$_=y/\0//'
ATCGTCGAGCG ACGTCCTGTCG
4
Do you all know of a good place I can study or learn about these short/compact functions? Is it called perl golf? What is perl golf?
Re: Array looping
by choroba (Cardinal) on Apr 12, 2017 at 08:10 UTC
It works for me:
```#!/usr/bin/perl
use strict;
use feature qw{ say };
use warnings;

sub test {
my (\$array1ref, \$array2ref) = @_;

my @array1 = @\$array1ref;
my @array2 = @\$array2ref;
my \$count = 0;
foreach my \$element (@array1) {
foreach my \$element2 (@array2) {
if (\$element eq \$element2) {
warn "\$element \$element2 same";
\$count++;
} else {
warn "\$element \$element2 different";
}
}
}
return \$count
}

my \$same = test([qw[ A T C G T C G A G C G ]],
[qw[ A C G T C C T G T C G ]]);
say "\$same matches.";

Or, do you want to walk both the arrays at the same time? Then you can use indices:

```sub test {
my (\$array1ref, \$array2ref) = @_;

my \$count = 0;
for my \$idx (0 .. \$#\$array1ref) {
my \$element  = \$array1ref->[\$idx];
my \$element2 = \$array2ref->[\$idx];
if (\$element eq \$element2) {
warn "\$element \$element2 same";
\$count++;
} else {
warn "\$element \$element2 different";
}
}
return \$count
}

Update: You can also just use shift, but you shouldn't use it on the dereferences directly if you want to keep the original arguments to the function unchanged.

```sub test {
my (\$array1ref, \$array2ref) = @_;
my @array1 = @\$array1ref;
my @array2 = @\$array2ref;

my \$count = 0;
for my \$idx (0 .. \$#array1) {
\$count++ if shift @array1 eq shift @array2;
}
return \$count
}

```(\$q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord
}map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+\$1,++print+eval\$q,q,a,
Re: Array looping
by kcott (Archbishop) on Apr 12, 2017 at 13:08 UTC

G'day Nansh,

That looks like you're overthinking the solution. I suspect you just need:

```my \$count = scalar grep { \$array1ref->[\$_] eq \$array2ref->[\$_] } 0 ..
+\$#\$array1ref;

Your example arrays have 11 elements each. With your nested foreach loops, that's 121 (11x11) comparisons; with the single iteration grep solution, that's only 11 comparisons. Given your example data looks like DNA sequences, your real data is likely to be many orders of magnitude larger: consider 10,000 vs. 100,000,000 comparisons.

While that specific line possibly solves your current issue, it's a general technique I suggest you add to your toolbox, for future reuse in similar situations, quite possibly with different types of data and different comparisons. Here's a command line example comparing two arrays of numbers:

```\$ perl -E 'my (\$a1, \$a2) = ([1,2,3],[1,3,3]); say scalar grep {\$a1->[\$
+_] == \$a2->[\$_]} 0..\$#\$a1'
2

— Ken

Re: Array looping
by Discipulus (Canon) on Apr 12, 2017 at 08:08 UTC
Hi nansh,

Are you working in a sub? my (\$array1ref, \$array2ref) = @_; indicate that yes you are in a sub.

You do not need to copy your array as in my @array1 = @\$array1ref; .. you can simply use @\$array1ref

Finally to loop over two arrays you simply foreach my \$el ( @arr1, @arr2) { ... so foreach my \$element (@\$array1ref, @\$array2ref) {

or using the ref passed into the sub directly foreach my \$element (@\$_[0], @\$_[1]) { will suffice if you as asked need to loop over two arrays simoultanely.

But you code seems to loop over the first array1 element AND foreach element of array2 to check they are equal. So you just do not need the else block.

If arrays are of the same lenght you can loop indexes instead (or use Data::Compare as yet suggested elsewhere)

```foreach my \$in (0..\$#array2) { \$count++ if \$array1[\$in] eq \$array2[\$in
+]

L*

There are no rules, there are no thumbs..
Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: Array looping
by Laurent_R (Canon) on Apr 12, 2017 at 08:53 UTC

Your code with nested foreach loops is comparing every single element of the secnd array with every single element of the first array. Is this really what you want to do? It doesn't make too much sense to me with the input data.

May be you want to traverse arrays in parallel, i.e., report a match is the nth item of array 1 is equal to the nth element of array 2. At least, this would make more sense to me with your data. In that case, you should not use nested loops, but one loop looping over the indexes (subscripts) and comparing the items for each subscript.

Please clarify what you're trying to achieve.

goal make work:
```my (\$array1ref, \$array2ref) = @_;
my @array1 = @\$array1ref;
my @array2= @\$array2ref;
my \$array1count = scalar @array1;
my \$array2count = scalar @array2;
my \$count = 0;

for (my \$array1index = 0; \$array1index < \$array1count; \$array1index++)
+ {
for (my \$array2index = 0; \$array2index < \$array2count; \$array2index++
+) {
if (\$array1[\$array1index] eq \$array2[\$array2index]) {
\$count++;
}
}
}

print "\$count";
print " matches found";
print \$/;

Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1187722]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (2)
As of 2024-05-26 18:28 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?

No recent polls found