Antonio Lopes
Antonio Lopes

Reputation: 512

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"?

Upvotes: 16

Views: 43600

Answers (7)

toolic
toolic

Reputation: 62236

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;

Outputs:

item with index 1 in list is 722065

Upvotes: 33

Sinan Ünür
Sinan Ünür

Reputation: 118166

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.

Upvotes: 15

Sean Morris
Sean Morris

Reputation: 1

use strict;
use Data::Dumper;

sub invert
{
 my $i=0;
 map { $i++ => $_ } @_;
}

my @a = ('a','b','c','d','e');

print Dumper @a;

print Dumper invert @a;

Upvotes: -1

newacct
newacct

Reputation: 122519

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;

Upvotes: 26

daotoad
daotoad

Reputation: 27234

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;

Upvotes: 6

ghostdog74
ghostdog74

Reputation: 343057

check out the Perl FAQ

Upvotes: 1

Mark Canlas
Mark Canlas

Reputation: 9583

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.

Upvotes: 2

Related Questions