Use table-lookup to test for membership in lists of strings; use any( ) for membership of lists of anything else .
Like grep, the any( ) function from List::MoreUtils (see "Utilities" in Chapter 8) takes a block of code followed by a list of values. Like grep, it applies the code block to each value in turn, passing them as $_. But, unlike grep, any( ) returns a true value as soon as any of the values causes its test block to succeed. If none of the values ever makes the block true, any( ) returns false.
This behaviour makes any( ) an efficient general solution for testing list membership, because you can put any kind of equivalence test in the block. For example:
# Is the index number already taken?if ( any { $requested_slot == $_ } @allocated_slots ) { print "Slot $requested_slot is already taken. Please select another: "; redo GET_SLOT; }
or:
# Is the bad guy at the party under an assumed name?if ( any { $fugitive->also_known_as($_) } @guests ) { stay_calm( ); dial(911); do_not_approach($fugitive); }
But don't use any( ) if your list membership test uses eq:
Readonly my @EXIT_WORDS => qw( q quit bye exit stop done last finish aurevoir ); # and later... if ( any { $cmd eq $_ } @EXIT_WORDS ) { abort_run( ); }
In such cases it's much better to use a look-up table instead:
Readonly my %IS_EXIT_WORD => map { ($_ => 1) } qw( q quit bye exit stop done last finish aurevoir );
# and later...if ( $IS_EXIT_WORD{$cmd} ) { abort_run( ); }
The hash access is faster than a linear search through an array, even if that search can short-circuit. The code implementing the test is far more readable as well.