SaAsh Techs
SaAsh Techs

Reputation: 169

Find item in Perl constant array

Hi Stack overfloweans,

I am finding a value in an array which is a constant allowed_value. If the main_value equals any of the values in allowed_value array, then I am printing the message 'Allowed value is correct'. So I have done the following piece of code.

use constant allowed_value => qw(value1 value2);

my $main_value = 'value2';

my @attr = (allowed_value);

print "Allowed value is correct" if grep $_ eq $main_value, @attr; 

Is there any way to make the code better and simplify the code ? Please help. Thanks in advance

Upvotes: 1

Views: 341

Answers (2)

Noah
Noah

Reputation: 193

Depending on how large your file is, i would use if (exists) and map the array into a hash. Once wrote a programm with a lot of greps, took ours to run through 400k lines, when i replaced most of the greps, came down to under 20 seconds.

Upvotes: 0

Schwern
Schwern

Reputation: 165198

grep is fine for small sets, but it has to search the whole set every time.

For larger sets you can do this a bit faster using List::Util's any() function. This has the advantage over grep that it will stop searching when it matches once. Assuming random data, on average you'll search half the list.

use strict;
use warnings;
use v5.10;
use List::Util 'any';

use constant allowed_values => qw(value1 value2);
my $main_value = 'value3';

say "Good" if any { $_ eq $main_value } allowed_values;

However, that still searching through even part of allowed_values every time. This is inconsequential for small sets of allowed values, but when it gets large it can get slow.

Instead use a hash as a set. It's a bit more work to set up, but it's more convenient and will perform the same no matter how large the set.

use strict;
use warnings;
use v5.10;

use constant allowed_values => {
    value1 => 1,  # any true value will do
    value2 => 1,
};
my $main_value = 'value2';

say "Good" if allowed_values->{$main_value};

And if your list of allowed values is long, you can generate the hash from a list avoiding a bunch of typing.

use constant allowed_values => {
    map { $_ => 1 }
    qw(value1 value2)
};

The downside is "constant" references aren't really constant. Only the reference is constant, the contents of that reference can be changed.

allowed_values->{foo} = 42;  # this is "fine"

If that's a concern, use Const::Fast instead.

use strict;
use warnings;
use v5.10;

use Const::Fast qw(const);
const my %allowed_values => (
    map { $_ => 1 }
    qw(value1 value2)
);
my $main_value = 'value2';

say "Good" if $allowed_values{$main_value};

Unless you really need an inlined constant, and generally you don't.

Upvotes: 4

Related Questions