6

I have an array of objects, and an array of acceptable return values for a particular method. How do I reduce the array of objects to only those whose method in question returns a value in my array of acceptable values?

Right now, I have this:

my @allowed = grep {
    my $object = $_;
    my $returned = $object->method;
    grep {
        my $value = $_;
        $value eq $returned;
    } @acceptableValues;
} @objects;

The problem is that this is a compound loop, which I'd like to avoid. This program is meant to scale to arbitrary sizes, and I want to minimize the number of iterations that are run.

What's the best way to do this?

2
  • 3
    Put the return values in a hash. Commented Apr 29, 2017 at 22:25
  • What number of objects and acceptable values do you expect? Commented Apr 29, 2017 at 22:57

2 Answers 2

7

You could transform the accepted return values into a hash

my %values = map { $_ => 1 } @acceptedValues;

And grep with the condition that the key exists instead of your original grep:

my @allowed = grep $values{ $_->method }, @objects;

Anyway, grep is pretty fast in itself, and this is just an idea of a common approach to checking if an element is in an array. Try not to optimize what's not needed, since it would only be worth in really big arrays. Then you could for example sort the accepted results array and use a binary search, or cache results if they repeat. But again, don't worry with this kind of optimisation unless you're dealing with hundreds of thousands of items — or more.

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

3 Comments

(exists is not actually needed since every value in the hash is true)
@ikegami true, I removed it for simplicity. Still, using exists would be slightly faster, right?
If it can't buy you time to brew a coffee, the speed optimization isn't worth it.
1

Elements supposed to be present in given arrays seems unique. So, I will make a hash containing the count of elements from both arrays. If there is any element with count greater than 1, it means its present in both the arrays.

my %values;
my @allowed;
map {$values{$_}++} (@acceptableValues, @objects);
for (keys %values) {
    push @allowed, $_ if $values{$_} > 1;
}

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.