In Perl, how can I find the index of a given value in an array?

$VAR1 = [
          '830974',
          '722065',
          '722046',
          '716963'
        ];

How can I calculate the array index for the value "722065"?


Solution 1:

The firstidx function from List::MoreUtils can help:

use strict;
use warnings;
use List::MoreUtils qw(firstidx);

my @nums = ( '830974', '722065', '722046', '716963' );
printf "item with index %i in list is 722065\n", firstidx { $_ eq '722065' } @nums;

__END__
item with index 1 in list is 722065

Solution 2:

using List::Util, which is a core module, unlike List::MoreUtils, which is not:

use List::Util qw(first);

my @nums = ( '830974', '722065', '722046', '716963' );
my $index = first { $nums[$_] eq '722065' } 0..$#nums;

Solution 3:

Here is how you would find all the positions at which a given value appears:

#!/usr/bin/perl

use strict;
use warnings;

my @x = ( 1, 2, 3, 3, 2, 1, 1, 2, 3, 3, 2, 1 );
my @i = grep { $x[$_] == 3 } 0 .. $#x;
print "@i\n";

If you only need the first index, you should use List::MoreUtils::first_index.

Solution 4:

If you only need to look up the one item, use firstidx as others have said.

If you need to do many lookups, build an index.

If your array items are unique, building an index is quite simple. But it's not much more difficult to build one that handles duplicate items. Examples of both follow:

use strict;
use warnings;

use Data::Dumper;

# Index an array with unique elements.
my @var_uniq  = qw( 830974 722065 722046 716963 );
my %index_uniq  = map { $var_uniq[$_] => $_ } 0..$#var_uniq;

# You could use hash slice assinment instead of map:
# my %index_uniq;
# @index_uniq{ @var_uniq } = 0..$#var_uniq

my $uniq_index_of_722065   = $index_uniq{722065};
print "Uniq 72665 at: $uniq_index_of_722065\n";
print Dumper \%index_uniq;

# Index an array with repeated elements.
my @var_dupes = qw( 830974 722065 830974 830974 722046 716963 722065 );
my %index_dupes;
for( 0..$#var_dupes ) {
    my $item = $var_dupes[$_];

    # have item in index?
    if( $index_dupes{$item} ) {
        # Add to array of indexes
        push @{$index_dupes{$item}}, $_;
    }
    else {
        # Add array ref with index to hash.
        $index_dupes{$item} = [$_];
    }
}

# Dereference array ref for assignment:
my @dupe_indexes_of_722065 = @{ $index_dupes{722065} };

print "Dupes 722065 at: @dupe_indexes_of_722065\n";
print Dumper \%index_dupes;

Solution 5:

Here's hastily written attempt at a reverse look-up using a hash.

my $VAR1 = [ '830974', '722065', '722046', '716963' ];

my %reverse;
$reverse{$VAR1->[$_]} = $_ for 0 .. @$VAR1 - 1;

print $reverse{722065};

This does not account for arrays with duplicate values. I do not endorse this solution for production code.