Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"

Code Interpretation

by Perl_Ally (Novice)
on Jul 28, 2014 at 15:32 UTC ( #1095377=perlquestion: print w/replies, xml ) Need Help??

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

I'm hoping somebody can help me interpret what's going on in the following line of code:

 my @refs = @allrefs[ sort {$a <=> $b} values %uni_refs ];

As far as I understand,  sort {$a <=> $b} values $uni_refs will sort $uni_refs by its values, numerically descending. Is this a correct interpretation?

Assuming I'm correct so far, what does it then mean to have @allrefs outside of the square brackets containing the sort?

Help greatly appreciated.

Replies are listed 'Best First'.
Re: Code Interpretation
by muba (Priest) on Jul 28, 2014 at 15:37 UTC

    You are correct so far.

    @allrefs is an array. To get an element out of an array, you use a syntax like $array[ INDEX ]. To get multiple elements out of an array, you'd use @array[ INDEX1, INDEX2, ..., INDEXN ]. That's what's going on here: we sort the values of the %uni_refs hash, and then use those values as the indexes of elements to extract from @allrefs and store them in @refs.

      Thanks so much muba! That makes perfect sense!

Re: Code Interpretation
by Athanasius (Bishop) on Jul 28, 2014 at 15:53 UTC

    Hello Perl_Ally, and welcome to the Monastery!

    muba has answered your question; I’ll just add a couple of comments:

    1. The syntax sort { $a <=> $b } does sort numerically, but in ascending order. To get descending order, you reverse $a and $b: sort { $b <=> $a }.

    2. The syntax @array[...] is called an array slice. See perldata#Slices.

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      Thanks so much for the clarification!

Re: Code Interpretation
by davido (Cardinal) on Jul 28, 2014 at 16:33 UTC

    Presumably the %uni_refs hash's values correspond to indices that should exist within @allrefs. So the values are sorted in ascending order forming a list of indices desired. Then they are used to take a slice of @allrefs, in that order.

    Seems like a pretty useful way to grab the wanted elements in a desired order, allowing for duplicates and skips as needed.


      Thanks Dave - this is a great "layman's terms" interpretation.

Re: Code Interpretation
by ikegami (Pope) on Jul 28, 2014 at 21:29 UTC

    Assuming every value of %uni_refs is a unique index of @allrefs (which I judge to be quite likely), the following is a solution that scales better (O(N) instead of O(N log N)).

    my %keep = map { $_ => 1 } values %uni_refs; my @refs = @allrefs[ grep $keep{$_}, 0..$#allrefs ];

      Edit: Apologies to ikegami for misreading his code. While the benchmark still more or less stands, my assertion that the output would differ was incorrect.

      Your code will not produce the same output as the OP's. You indeed removed an O(N log N) loop, but at the cost of the sort. Even then, thanks to the grep and extra hash loop versus slice, the OP's (sorted) performance is 300% better than your unsorted code. Both unsorted, the gap widens to nearly 1000% with N = 1x105.

      With N = 1x106, the gap shrinks a bit to 214% and 738%, respectively.

      Perhaps I'm missing your point, though? Edit: Yup!

        Your code will not produce the same output as the OP's.

        As long as grep doesn't change the order of 0..$#allrefs, I'd expect the result to be in the same order as by the OP.

        About the performance point, this depends on wether %uni_refs has the same size as @allrefs, or not.
        If %uni_refs is just a small part of @allrefs, ikegami's solution is faster even with the additional sort...

        Update: Oops, I should take a course in reading benchmarks ... map+grep is slower, anyway.
        Yet I'm not completely convinced. There must be an edge case where it is faster :-)
Re: Code Interpretation
by blue_cowdawg (Monsignor) on Jul 28, 2014 at 15:43 UTC

    Doesn't look like it does anything. Here is what I started with:

    use strict; use Data::Dumper; my @allrefs; my %uni_refs = ( qw [ a 1 b 2 c 3 ] ); print Dumper \%uni_refs; my @refs = @allrefs[ sort {$a <=> $b} values %uni_refs ]; print Dumper \@allrefs; print Dumper \@refs;
    and here is what the output looks like:
    $VAR1 = { 'c' => '3', 'a' => '1', 'b' => '2' }; $VAR1 = []; $VAR1 = [ undef, undef, undef ];
    Question is: what was the intended outcome?

    Peter L. Berghold -- Unix Professional
    Peter -at- Berghold -dot- Net; AOL IM redcowdawg Yahoo IM: blue_cowdawg

      blue_cowdawg: Thanks for the attention.

      I wasn't sure of the intent, which is why I was looking for help interpreting. This is an existing script written by somebody else which I'm hoping to update to be more useful.

      The quoted line of code comes at the end of a sub. @allrefs should be an already populated array, which is why your output shows undef.

            @allrefs should be an already populated array, which is why your output shows undef.

        I had a hunch that was the case. This is why you need to include pre-assignments in your code sniglets.

        Peter L. Berghold -- Unix Professional
        Peter -at- Berghold -dot- Net; AOL IM redcowdawg Yahoo IM: blue_cowdawg
Re: Code Interpretation ( ppi_dumper )
by Anonymous Monk on Jul 28, 2014 at 20:56 UTC
A reply falls below the community's threshold of quality. You may see it by logging in.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1095377]
Approved by muba
Front-paged by davies
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (5)
As of 2020-07-02 09:53 GMT
Find Nodes?
    Voting Booth?

    No recent polls found