0

I have two arrays @input0 and @input1. I would like a for loop that goes through every value in @input1 and if the value exists in @input0, the value is saved in a new array @input.

All arrays contain numbers only. There are a maximum of 10 numbers per array element (see below):

@input0 = {10061 10552 10553 10554 10555 10556 10557 10558 10559 10560, 10561 10562 10563 10564 10565 10566 10567 10573 10574 10575, ...}

@input1 = {20004 20182 ...}
1
  • 1
    @input0 = {10061 10552 ...., 10561...} is not valid perl syntax, and would give errors such as Number found where operator expected. You'd need to quote the strings "10061 10552 ...". Also, the curly brackets {} create a hash reference. You want regular parens () when assigning to an array. Commented Feb 6, 2012 at 14:53

4 Answers 4

7

The most concise and idiomatic way to achieve this in Perl is not via using "for" loop but map and grep

my %seen0 = map { ($_ => 1) } @input0;
my @input = grep { $seen0{$_} } @input1;

If you specifically want a for loop, please explain why map/grep approach does not work (unless it's a homework in which case the question should be tagged as one)

Sign up to request clarification or add additional context in comments.

2 Comments

This doesn't seem to work. I guess its because I have more than one number per array element (up to 10, separated by spaces). Sorry, should have mentioned that. So am I best splitting the array into single numbers per element first? Thanks
@charleshendry - if you have a string that's space separated, it's not called an "array". You need to give a more exact descriptions and examples
2

Short, sweet and slow:

my @input = grep $_ ~~ @input0, @input1;

Verbose and faster with for loop:

my %input0 = map {$_, 1} @input0;
my @input;

for (@input1) {
    push @input, $_ if $input0{$_};
}

3 Comments

Smart Match only works in Perl 5.10 and on and doesn't work in earlier.
This is also slower for large arrays, since it does O(N*M) scanning, as opposed to I(N+M) as map+grep
That is true, but you beat me to the idiomatic solution. If something though, this solution makes it easier to tell at first glance that it's creating an intersection of two arrays.
1

You could also use a hashslice + grep:

my %tmp ;
@tmp{@input0} = undef ; # Fill all elements of @input0 in hash with value undef
my @input = grep { exists $tmp{$_} } @input1 ; # grep for existing hash keys

Comments

0

dgw's answer was nearly there, but contained a couple of things which aren't best practice. I believe this is better:

my %input0_map;
@input0_map{ @input0 } = ();
my @input = grep { exists $input0_map{$_} } @input1;

You should not name a variable 'tmp' unless it's in a very small scope. Since this code snippet isn't wrapped in a brace-block, we don't know how big the scope is.

You should not assign into the hash slice with a single 'undef', because that means the first element is assigned with that literal undef, and the other elements are assigned with implicit undefs. It will work, but it's bad style. Either assign them all with a value, or have them ALL assigned implicitly (as happens if we assign from the empty list).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.