Liam Liam - 1 year ago 40
Perl Question

Match array based on existing array

I have two arrays,

my @test = ('a','b','c','d','e',f,'g','h');

my @test2 = ('h','b','d');

I'm attempting to loop through the array
, and match elements against those in
deleting those elements that do not exist.

I have the following code:

foreach my $header (@test) {
if( exists $test2[$header]){
# do nothing
else {
delete $test[$header];

So, I want array @test to look like this (ignore the fact this could be sorted alphabetically):

my @test = ('b','d','h');

However currently my array remains the same after the foreach loop, can anyone suggest why?

Answer Source

You're misunderstanding what 'header' is set to. It's set to (an alias of) the value in the array.


foreach my $header (@test) {
   print $header,"\n";

Will give you a, b, c etc.

However, then you're trying to access $test2['a'] which isn't valid, because it should be numeric.

So actually, a good case study in why you should use strict and warnings because this would have told you the problem:

Argument "a" isn't numeric in array or hash lookup at 
Argument "b" isn't numeric in array or hash lookup at 


So it's not actually doing anything.

You shouldn't use delete in this way either though, because you're deleting from a list whilst iterating it. That's not good, even without the fact that it's nonsense to use a letter as an array index.

You could do it like this instead though:

#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;

my @test = ('a','b','c','d','e','f','g','h');

my @test2 = ('h','b','d');

my %is_in_test2 = map { $_ => 1 } @test2; 
@test = grep { $is_in_test2{$_} } @test;

print Dumper \@test;

If you do want to iterate by index, you can do it like this:

for my $index ( 0..$#test ) {  
   print "$index => $test[$index]\n";

But I would still suggest that deleting whilst iterating isn't a great plan, because modifying a thing you're iterating it ( and aiming to resize the array) is a good way to end up with strange bugs.

So whilst you could:

for my $index ( 0..$#test ) {  
   print "$index => $test[$index]\n";
   delete $test[$index] if not $is_in_test2{$test[$index]};
print Dumper \@test;

What you'll end up with is:

$VAR1 = [

For the more general case there is a a FAQ: How do I computer the difference/intersection of two arrays