Reputation: 39
My grep function doesn't return the expected occurrence
I have tried grep function and use conditional coding
@SA = (SA2,SA22,SA3,SA29,SA4,SA2,SA3,SA5,SA222,SA30);
foreach $ab(@SA){
my $cntab = grep (/$ab/,@SA);
print "cntab = $cntab\n";
if ($cntab >1){
push @SA_ab, $ab;
}
}
print "SA_ab = @SA_ab\n";
Expected result:
cntab = 2
cntab = 1
cntab = 2
cntab = 1
cntab = 1
cntab = 2
cntab = 2
cntab = 1
cntab = 1
cntab = 1
SA_ab = SA2 SA3
Actual result:
cntab = 5
cntab = 2
cntab = 3
cntab = 1
cntab = 1
cntab = 5
cntab = 3
cntab = 1
cntab = 1
cntab = 1
SA_ab = SA2 SA22 SA3 SA2 SA3
Upvotes: 0
Views: 49
Reputation: 385764
grep
doesn't perform any matching at all. It simply executes the provided expression (or code block) for each element.
In the provided expression, you evaluate a regex match operator. It performs an unanchored match by default.
You could use
grep(/^\Q$ab\E\z/, @SA)
but there's no point in using a relatively slow regex match to check for string equality. You could use
grep($_ eq $ab, @SA)
which most people would write as
grep { $_ eq $ab } @SA
With this fix, you get
cntab = 2
cntab = 1
cntab = 2
cntab = 1
cntab = 1
cntab = 2
cntab = 2
cntab = 1
cntab = 1
cntab = 1
SA_ab = SA2 SA3 SA2 SA3
The values for cntab
are now correct, but not the value for SA_ab
. That's because there's a second problem.
The second problem is that you add elements whose count is larger than 1 each time the appear in the list. You only want to add them once.
The following fixes this issue (along with scoping issues):
use strict; # Always use this!
use warnings; # Always use this!
my @SA = qw( SA2 SA22 SA3 SA29 SA4 SA2 SA3 SA5 SA222 SA30 );
for my $ab (@SA) {
my $cntab = grep { $_ eq $ab } @SA;
print "cntab = $cntab\n";
}
my %counts;
my @SA_ba;
for my $ab (@SA) {
++$counts{$ab};
if ($counts{$ab} == 2) {
push @SA_ab, $ab;
}
}
print "SA_ab = @SA_ab\n";
However, your approach is quite inefficient. You are performing a number of operations in the order of N2 when a number in the order of N is sufficient.
use strict; # Always use this!
use warnings; # Always use this!
my @SA = qw( SA2 SA22 SA3 SA29 SA4 SA2 SA3 SA5 SA222 SA30 );
my %counts;
my @SA_ba;
for my $ab (@SA) {
++$counts{$ab};
if ($counts{$ab} == 2) {
push @SA_ab, $ab;
}
}
for my $ab (@SA) {
print "cntab = $counts{$ab}\n";
}
print "SA_ab = @SA_ab\n";
If you don't need to print the counts, the above can be reduced to the following:
use strict; # Always use this!
use warnings; # Always use this!
my @SA = qw( SA2 SA22 SA3 SA29 SA4 SA2 SA3 SA5 SA222 SA30 );
my %counts;
my @SA_ba = grep { ++$counts{$_} == 2 } @SA;
print "SA_ab = @SA_ab\n";
Upvotes: 2