tags:

views:

397

answers:

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

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

+2  A: 

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.

Mark Canlas
In the case of duplicate values you'll just get the first element that matches. This can be really useful if a long-lived array is queried more than once.
Leonardo Herrera
I'm not sure if I understand the comment above, but the way the code is written, in the case of duplicate values, the highest index wins.
Mark Canlas
+15  A: 

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
toolic
I like the use of List::MoreUtils, good answer!
chollida
Using numeric comparison with string values is not a good idea (even though it does not matter in this case. What happens when you have ZIP codes and `07030` in the list. `perl -e 'print 0 + (07030 == "07030")'`
Sinan Ünür
@Sinan: you are correct. I edited my answer to perform a string comparison.
toolic
+1  A: 

Check out the discussion on perlmonks: http://www.perlmonks.org/?node_id=66003

Courtland
Be aware that this is a link to a **golf** contest. While the linked site demonstrates different algorithms and techniques with significant pedagogical value, care should be taken when adapting this code for production use. Remember, **golf** is judged primarily on have the smallest number of characters--this is not a good way to think about your production code.
daotoad
+2  A: 

check out the Perl FAQ

Everyone ought to read the FAQ list at least once a year.
Sinan Ünür
RRTFM-ing (Re-reading the fine manual) is an amazingly rewarding experience. The first time I read the docs, much of it went right over my head. Each subsequent reading has revealed new meaning. It's amazing the number of things you can learn by (re)reading the manual!
daotoad
I'd be satisfied if most people at least read it once. People constantly ask how relevant the FAQ is, and StackOverflow has been a great natural experiment: everyone re-asks the FAQ questions.
brian d foy
@daotoad: maybe that's because I keep changing the FAQ on you. :)
brian d foy
+4  A: 

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.

Sinan Ünür
Honestly. Lose the mention of $[. It's obscure, IIRC deprecated and there is no honest reason to use it.
tsee
@tsee You right. It was silly of me to even mention `$[`.
Sinan Ünür
That's Perl street cred material, thought :-)
Leonardo Herrera
A: 

it's okay, everyone was new to perl at one point

$a is the element to print the index of in @list...

my @list = (124124, 323, 156666, 124412, 3333, 4444444444, 124124124, 24412);
my $a = 4444444444;

print 
substr($_=($,=
chr($==39)).(
join$,,@list).$,,$=-$=,
index$_,$,.$a.$,)=~
tr/'//+$=---$=;
John
Off-by-one error? It prints out '6', but I would expect '5'.
toolic
If your purpose is to help a newbie, you should not post obfuscated code. If your purpose is to impress people, you might want to spell Perl correctly.
Sinan Ünür
@toolic: it's the 6th element of the list, i didnt start at 0. if you want to start at 0 you'll have to change the last line to tr/'//+$=-$=;
John
@john: The question specifically asks for the index. Indices start at zero. Not only have you posted an unhelpful answer in a misguided effort to look cool, but you have failed to understand the question in the first place.
Adam Bellaire
@Adam Bellaire: You are correct, I did fail to understand the question. However, as someone has already pointed this out in a prior reply, your statement is as redundant as it is wasteful of server place. Please employ my patch to my code as I specified above and reevaluate the felicitousness of my coolness effort!
John
This answer is a waste of server space. You can delete answers to save your dwindling reputation though. It will still waste server space though. :)
brian d foy
+4  A: 

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;
daotoad
+1  A: 

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;
newacct