user6201481
user6201481

Reputation: 39

I don't know the grep function will perform full element or partial element match

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

Answers (1)

ikegami
ikegami

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

Related Questions