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.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
$ perl -alpE '$_=($F[0]^$F[1])=~tr{\0}{}'
ATCGTCGAGCG ACGTCCTGTCG
4
^D
| [reply] [Watch: Dir/Any] [d/l] |
|
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!
| [reply] [Watch: Dir/Any] |
|
|
$ perl -pale '$_^=$F[1];$_=y/\0//'
ATCGTCGAGCG ACGTCCTGTCG
4
| [reply] [Watch: Dir/Any] [d/l] |
|
|
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?
| [reply] [Watch: Dir/Any] |
|
Re: Array looping
by choroba (Cardinal) on Apr 12, 2017 at 08:10 UTC
|
#!/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,
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: Array looping
by kcott (Archbishop) on Apr 12, 2017 at 13:08 UTC
|
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
| [reply] [Watch: Dir/Any] [d/l] [select] |
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.
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: Array looping
by Laurent_R (Canon) on Apr 12, 2017 at 08:53 UTC
|
Your goal is not clear.
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. | [reply] [Watch: Dir/Any] |
|
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 $/;
| [reply] [Watch: Dir/Any] [d/l] |