Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

grep surprise

by morgon (Priest)
on Nov 11, 2018 at 21:30 UTC ( [id://1225595]=perlquestion: print w/replies, xml ) Need Help??

morgon has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

I usually just grep through arrays, but recently I was not looking for an array-element, but for the index of an array-element, so I tried this:

use strict; my @array=(1,2); my $i1 = grep { $array[$_] == 1 } (0..$#array); my $i2 = grep { $array[$_] == 2 } (0..$#array); my $i3 = grep { $array[$_] == 3 } (0..$#array); print "<$i1> <$i2> <i3>\n";
I would have expected an output of "<0> <1> <>" (as the index where the value is 1 is 0, the index where the value is 2 is 1 and there is no index with a value of 3), but instead I get "<1> <1> <0>".

Why is that?

Replies are listed 'Best First'.
Re: grep surprise
by AnomalousMonk (Archbishop) on Nov 11, 2018 at 21:37 UTC

    Because grep evaluated in scalar context (as you are doing) returns the number of elements of the input list that satisfy the condition.


    Give a man a fish:  <%-{-{-{-<

Re: grep surprise
by ikegami (Patriarch) on Nov 11, 2018 at 21:39 UTC

    grep in scalar context returns the number of matches. To get the first match, you can use the following:

    my ($i1) = grep { $array[$_] == 1 } 0..$#array; my ($i2) = grep { $array[$_] == 2 } 0..$#array; my ($i3) = grep { $array[$_] == 3 } 0..$#array;

    Might be worth creating a lookup table.

    my %lookup = map { $array[$_] => $_ } 0..$#array; my $i1 = $lookup{1}; my $i2 = $lookup{2}; my $i3 = $lookup{3};

      The second one returns that last index though (because if there are duplicates, each new occurence overwrites the previous one). This is not an issue of course if the values are unique, in which case it might make sense to store them in a hash in the first place.

Re: grep surprise
by LanX (Saint) on Nov 11, 2018 at 22:47 UTC
    RTFM?

    grep

    In scalar context, returns the number of times the expression was true.

    and it's $i3 not i3

    anyway others may profit from a working solution, just replacing grep with first

    use strict; use warnings; use List::Util qw/first/; my @array=(1,2); my $i1 = first { $array[$_] == 1 } (0..$#array); my $i2 = first { $array[$_] == 2 } (0..$#array); my $i3 = first { $array[$_] == 3 } (0..$#array); print "<$i1> <$i2> <$i3>\n";
    Use of uninitialized value $i3 in concatenation (.) or string at d:/tm +p/first.pl line 13. <0> <1> <>

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

      ikegami shows the way to do it above.

      Using List::Util::first works of course but does not add any value at all.

        > does not add any value at all.

        Not very surprising that you think that way.

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

        A reply falls below the community's threshold of quality. You may see it by logging in.
Re: grep surprise
by BillKSmith (Monsignor) on Nov 12, 2018 at 11:56 UTC
    Refer to the function indexes in the module List::MoreUtils.
    $type morgon2.pl use strict; use warnings; use List::MoreUtils 'indexes'; my @array=(1,2); my $i1 = indexes { $array[$_] == 1 } (0..$#array); my $i2 = indexes { $array[$_] == 2 } (0..$#array); my $i3 = indexes { $array[$_] == 3 } (0..$#array); print "<$i1> <$i2> <$i3>\n"; $perl morgon2.pl Use of uninitialized value $i3 in concatenation (.) or string at morgo +n2.pl line 10. <0> <1> <>
    Bill
        Since you are testing the case where all entries are unique, you may want to add benchmarks for hash lookups.

        Actually two: there is no doubt that a lookup is way faster, the essential question is if the initialization of the hash needs to be included.

        In the later case I'd prefer a hash slice then.

        @lookup{@array} = (0.. $#array);

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

Re: grep surprise
by Anonymous Monk on Nov 11, 2018 at 22:07 UTC
    dont use arrays with numbers as elements for testing, use letters

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1225595]
Approved by marto
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (2)
As of 2024-04-16 20:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found