tags:

views:

133

answers:

6

I want to search for all elements in an array 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.

+1  A: 

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;
}
eugene y
I think that's too restrictive... The OP just said he wanted the element printed if it started with ANY of the elements in the other array. This imposes a one-to-one mapping.
Platinum Azure
I can't undo my -1 for some reason... Can you do me a favor and edit this once more so I can undo it?
Platinum Azure
The second one with grep still doesn't do what the OP wants. It prints the word you're using to grep instead of the value in the array.
Weegee
@Weegee: corrected.
eugene y
Nice. +1 from me.
Weegee
A: 

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.

davorg
That will potentially result in duplicates (if `@temp` has multiple elements which start the same and could therefore match something in `@array` with each of them).
Platinum Azure
Thanks for your answer. And I did copy paste "actual code and output". I don't use strict although I know its a standard. I just use perl for quick string manipulation although I know I should be using strict.
omglol
A: 
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.

Platinum Azure
umm..quick followup..What if you wanted to print only the first match?
omglol
A: 

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
M42
Can the downvoter explain why ?
M42
+2  A: 

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;
    }
}
Weegee
Works perfect. Thanks :)
omglol
A: 

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.

brian d foy