开发者

How can I select certain elements from a Perl array?

开发者 https://www.devze.com 2023-01-19 12:53 出处:网络
I want to search for all elements in an ar开发者_如何学Pythonray which have the same starting set of characters as an element in another array. To make it clear:

I want to search for all elements in an ar开发者_如何学Pythonray which have the same starting set of characters as an element in another array. To make it clear:

@array = ("1a","9","3c");
@temp =("1","2","3");

I want to print only 1a and 3c. When I try to use the following program it prints out all the elements in the array instead of the two I want:

foreach $word (@temp)
{
    if( grep /^$word/ , @array) 
    {
        print $_;
    }
}

Any insights will be appreciated.


This answer will do what the OP wants as well as prevent any duplicates from printing on the screen through the use of a hash lookup.

#!/usr/bin/perl

use strict;
use warnings;

my @array = ("1a","9","3c","3c");
my @temp =("1","2","3");

my %dups_hash;

for my $w (@temp) {
    my ($match) = grep /^$w/, @array;

    # Need to check if $match is defined before doing the hash lookup.
    # This suppresses error messages for uninitialized values; if defined($match) is
    #  false, we short circuit and continue in the loop.
    if(defined($match) && !defined($dups_hash{$match})) {
        print $match;
    }
}


If you want to match the elements pairwise, you can do it this way:

for my $i (0..$#array) {
    print $array[$i], "\n" if $array[$i] =~ /^$temp[$i]/
}

Otherwise you can use grep:

for my $i (0..$#array) {
    print "$array[$i]\n" if grep /^$temp[$i]/, @array;
}


For this sort of problem, the trick is to not scan the array more than you have to. I think Knuth wrote an entire book about that. :) Often, we get stuck in these situations because we stick too closely to the thing we tried first.

You can construct a single regular expression from all of the patterns that you want to search then scan the array once:

use Regexp::Assemble;

my @array = qw( 1a 9 3c );
my @temp  = qw( 1 2 3 );

my $ra = Regexp::Assemble->new;
$ra->add( @temp );

my $pattern = $ra->re;
print "pattern is [$pattern]\n";

print join ' ', grep /\A$pattern/ , @array;

This sort of thing works when you don't care which part of the pattern matches as long as it matches.


When I try to use the following program it prints out all the elements in the array instead of the two I want.

No it doesn't. As written, it prints nothing. With strict turned on, it prints "Global symbol "$temp" requires explicit package".

Fixing that obvious typo and turning on warnings, it prints "Use of uninitialized value $_ in print" twice.

Please don't waste our time, by showing us code that either doesn't compile doesn't do what you say. Don't retype code into this site - cut and paste the actual code that you're using.

The solution to your problem is going to be something like:

#!/usr/bin/perl

use strict;
use warnings;

my @array = ("1a","9","3c");
my @temp =("1","2","3");

foreach my $word (@temp) {
  print grep /^$word/ , @array;
}

But there are probably more efficient ways of doing it.


map { print "$_\n" } grep { my $a = $_; grep {$a =~ /^$_/} @temp } @array

Basically, the outer grep selects the elements for which 1 or more of the elements in @temp matches the inner regex-- that is, it selects all elements which start with one (or more) of the elements in @temp.


To avoid blank lines if grep return empty list :

#!/usr/bin/perl
use strict;
use warnings;
use 5.10.1;

my @array = qw(1a 9 3c 1g);
my @temp =(1, 2, 3);
foreach my $word(@temp) {
  my @l = grep{/^$word/}@array;
  say "@l" if @l;
}

Output :

1a 1g
3c
0

精彩评论

暂无评论...
验证码 换一张
取 消