Pathologically Eclectic Rubbish Lister PerlMonks

### Finding index of an entry in an Array

by monkfan (Curate)
 on Dec 07, 2007 at 01:47 UTC Need Help??
monkfan has asked for the wisdom of the Perl Monks concerning the following question:

Dear fellow monks,

For example I have an array as a repository and string as input.
```my \$input = \$ARGV[0] || 'bar';
my @repo = qw (foo bar qux);
What's the compact way to find the index of 'bar' in @repo, such that finally it returns '2' (index in @repo).

Regards,
Edward

Replies are listed 'Best First'.
Re: Finding index of an entry in an Array
by jrsimmon (Hermit) on Dec 07, 2007 at 02:04 UTC
Assuming you're wanting a simple iteration and not some type of sort algorithm, this will do the trick.
```my \$index = 0;
my \$input = \$ARGV[0] || 'bar';
my @repo = qw (foo bar qux);
\$index++ until @repo[\$index] eq \$input or \$index > \$#repo; #don't want
It's worth noting that in your example, bar is at index 1, not index 2.

Update: Fixed the typo pointed out by dwu
```\$index++ until @repo[\$index] eq \$input or \$i > \$#repo;
Did you perhaps mean:
```\$index++ until \$repo[\$index] eq \$input or \$index > \$#repo;

since you don't declare \$i anywhere, and I'd have a hard time not getting that to loop forever when I started comparing zero to \$#repo :)

Edit: thanks to IRCperson for spotting \$repo[\$index]

Re: Finding index of an entry in an Array
by Fletch (Chancellor) on Dec 07, 2007 at 03:20 UTC

Aside from the fact that the index of 'bar' in your sample array is 1 not 2 (remember array indexen start at 0) . . .

```use List::Util qw( first );
my \$idx = first { \$repo[ \$_ ] eq 'bar' } 0..\$#repo;

The cake is a lie.
The cake is a lie.
The cake is a lie.

Also, List::MoreUtils has a first_index method:
```use List::MoreUtils;
my \$input = 'qux';
my @repo = qw (foo bar qux);

Print List::MoreUtils::first_index {\$_ eq \$input} @repo;
This concept works without List::Util as well,
```my @array = qw(dog cat mat bat hat);
my (\$idx) = grep { \$array[\$_] eq 'bat' } 0 .. \$#array;
Update: Fletch noted an issue, when I was quickly testing on the command line I wasn't assigning to a variable, just printing (e.g. print grep { ... } 0 .. \$#array, which evaluates in list context, not scalar context as I through up here with the assignment. Adding the parens clears that up. (Thanks Fletch).

---
s;;:<).>|\;\;_>?\\^0<|=!]=,|{\\$/.'>|<?.|/"&?=#!>%\\$|#/\\$%{};;y;,'} -/:-@[-`{-};,'}`-{/" -;;s;;\$_;see;
Warning: Any code posted by tuxz0r is untested, unless otherwise stated, and is used at your own risk.

Not without parens (since grep in scalar context returns the number of matching elements) and not without searching the entire list of indexen (which of course could be what the OP really wants, the indexen of all matching elements).

```my( \$idx ) = grep { \$array[ \$_ ] eq 'bar' ) 0..\$#array;
my @indexen = grep { \$array[ \$_ ] eq 'bar' } 0..\$#array;

That aside, yup that's another way to do it. :)

The cake is a lie.
The cake is a lie.
The cake is a lie.

Re: Finding index of an entry in an Array
by sh1tn (Priest) on Dec 07, 2007 at 03:18 UTC
```{map(\$_ eq 'bar' && last || \$index++,  @repo)};

#or

{grep(/^\Q\$input\E\$/ && last || \$index++,  @repo)};

Re: Finding index of an entry in an Array
by Anonymous Monk on Dec 07, 2007 at 03:41 UTC
if you are doing a sufficiently large number of look-ups in the  @repo array, it will be advantageous to do a cached look-up of the index. (this will be all the more true if the array is large.)

```perl -wMstrict
-e "my @repo = qw(foo bar qux bar zot);  my %repo_index;
\$repo_index{\$repo[\$_]} = \$_ for reverse 0 .. \$#repo;
print \$repo_index{bar};"
1

note that if there are duplicate entries in the array, the index of the first (lowest index) entry will be returned. eliminate the  reverse call to have it the other way.

note that if there are duplicate entries in the array, the index of the first (lowest index) entry will be returned. eliminate the reverse call to have it the other way.
This should be restated to say exactly two duplicate entries. A third or further duplicates would be undetectable with this method.
i don't understand your point. i would not say my approach was able to directly detect any number of duplicates, whether 2, 3 or more. (the only, and somewhat awkward, way to detect the presence of duplicates with this specific caching approach would be to build two caches, one based on ascending indices, the other based on descending indices, and compare the two indices derived from the two caches. if they are not the same, two or more duplicates must exist. however, i can think of better ways to handle this sort of info.)

the point i was trying, perhaps clumsily, to make in my original post was that my method, in common with all the other approaches that had appeared by then, would, due to the use of reverse, return the first (i.e., lowest) index of a match in the case of duplicates, but that a variation could easily be had that would return the last/highest index.

since my original post, i see that some solutions have been posted that return the indices of all matches, which i did not understand to be a requirement of the original question. oh, well...

Re: Finding index of an entry in an Array
by ysth (Canon) on Dec 07, 2007 at 05:56 UTC
Wanting to do this is often a clue that you shouldn't have been using an array in the first place.
Re: Finding index of an entry in an Array
by l.frankline (Hermit) on Dec 07, 2007 at 06:23 UTC
```my \$input = \$ARGV[0] || 'bar';
my @repo = qw (foo bar qux);
map{ print \$_ if \$repo[\$_] eq \$input }  0..\$#repo;

Don't put off till tomorrow, what you can do today.

Re: Finding index of an entry in an Array
by poolpi (Hermit) on Dec 07, 2007 at 08:39 UTC
```#!/usr/bin/perl
use strict;
use warnings;

my \$input = \$ARGV[0] || 'bar';
my @repo  = qw(foo baz bar boo);

my \$i;
map{ print \$i if /\$input/; \$i++ } @repo;
HTH,
PooLpi
Re: Finding index of an entry in an Array
by Anonymous Monk on Dec 07, 2007 at 16:33 UTC
a caching approach to returning all indices of an item in an array:

```perl -wMstrict
-e "my @repo = qw(foo bar qux bar bar zot);  my %repo_indices;
push @{ \$repo_indices{\$repo[\$_]} }, \$_ for 0 .. \$#repo;
print qq(@{ \$repo_indices{bar} });"
1 3 4

Create A New User
Node Status?
node history
Node Type: perlquestion [id://655564]
Approved by GrandFather
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others surveying the Monastery: (4)
As of 2017-12-12 01:13 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
What programming language do you hate the most?

Results (321 votes). Check out past polls.

Notices?