Some sort questions - especially hashes

Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

Threaded View
This started out as one question but in trying to solve my problem I  
got side tracked - as you do :-)

In the "Perl Cookbook" page 140 under sorting lists there is the  
following code:

@ordered = sort { $a->name cmp $b->name } @employees;

Where has 'name' come from? and what is in @employees such that  
$a->name means something? I can't work it backwards as it were to  
figure it out.  

Now the actual problem.

I have a script that is building an HTML table. The table is built  
from a hash. The top level entries of the hash are anonymous arrays  
the elements of which are the columns.  

At present there is a chunk of duplicated formatting code depending on
which of two columns I sort over. Yesterday the inevitable happened in
that I changed the formatting of one set and forgot to make the same  
change in the other. The "curse of the duplicated code" :-)

So it got me wondering if I could code one formatting loop and  
dynamically set the sort up or down.

$foo = \&sortup;
$foo = \&sortdown if $bar;

foreach (sort $foo keys ......

But I recall scope problems in the past using suborutines that seem  
solved if one used sort { ..... } syntax

At present one of the sorts looks like:

    foreach my $url (sort [0] <=>  
$$urlsref[0] or $a cmp $b} keys %} ) #  
count descending

Dave Saville

Re: Some sort questions - especially hashes

On 10/10/13 14:44, Dave Saville wrote:
Quoted text here. Click to load it

 From the perldoc: "where the elements to be compared are passed into  
the subroutine as the package global variables $a and $b".

So in that block (within the braces) $a and $b represent the two sides  
of every comparison that the sort will make; conceptually at any rate  
the sort invokes your block, passing $a and $b to it, and makes its sort  
decision on the final value.

I don't know what @employees consists of either, but whatever it is the  
construct "$element_of_employees->name" must have some value.  An array  
of objects which all implement a "name" method would do.

It's just a code fragment; its message is that that you can use whatever  
comparison code you like within your block, not just "<=>", "cmp" and so on.


Henry Law            Manchester, England

Re: Some sort questions - especially hashes


Quoted text here. Click to load it

Yes I understand that part.

Quoted text here. Click to load it

Ah, I thought it might be some sneaky way of sorting on hash keys  
assuming the array contained refs to hashes.  

Quoted text here. Click to load it

Dave Saville

Re: Some sort questions - especially hashes


Quoted text here. Click to load it

sub asc
    return $a <=> $b;

sub desc
    return $b <=> $a;

my @in = map { int(rand(100)); } 0 .. 9;
my $cmp;

$cmp = \&asc;
print($_, "\n") for sort $cmp @in;


$cmp = \&desc;
print($_, "\n") for sort $cmp @in;

works as it should. What 'scope problems' are you referring to?

Re: Some sort questions - especially hashes

On Thu, 10 Oct 2013 14:28:13 UTC, Rainer Weikusat  

Quoted text here. Click to load it


IIRC I was several depths down in subroutines and using a "sort  sub"  
syntax to sort and it was similar to this problem with a complicated  
deep hash to sort on and it was not sorting correctly until someone on
here pointed out that some part of it was out of scope. It was a long  
time ago. But it *may* have been like this:

use .....



sub foo{
     .... sort bar .....

sub bar {

IOW foo and bar are on the same "level" and possibly bar should have  
been defined inside foo.

Dave Saville

Re: Some sort questions - especially hashes

Quoted text here. Click to load it

You can get problems if the sort call and the sub you are sorting by are
in different packages.

Quoted text here. Click to load it

Named subs should never be defined inside other named subs in Perl. It
doesn't achieve anything useful and sometimes has confusing side-effects
(you will get a 'variable will not stay shared' warning, and the sub
won't see the lexicals you necessarily expect).

This probably doesn't apply to the new 'my sub's in 5.18; I haven't
investigated those yet.


Re: Some sort questions - especially hashes

Quoted text here. Click to load it

Actually, one will get problems in this case as sort uses the
package-variables $a and $b to pass the objects-to-be-compared into the
comparison routine and if that's not in the same package as the sort call,
naively written code will use a different $a and $a (namely, those of
the package the subroutine belongs to). Symbolic references could be
used to work around that (possibly together with no strict 'refs'):

package AlienCompare;

sub desc {
    return $ <=> $;

package Orkshire;

my @in = map { int(rand(100)) } 0 .. 9;

print($_, "\n") for sort AlienCompare::desc @in;


Quoted text here. Click to load it

Depending on the situation, it might: PostgreSQL functions written in
Perl end up being compiled into anonymous subroutines. Insofar things
get complicated enough that more than one Perl subroutine is needed, the
additional ones have to be defined inside the/ a anonymous subroutine
created by the database server (it is possible to escape from the
anonymous routine by terminating it with a top-level }, add some 'free
code' and then get back into a different anonymous sub at the end of the
Postgres function definition, as you suggested a while ago, but that's a
trick I'd rather avoid).

Quoted text here. Click to load it

IMHO, the warning itself is such a confusing side effect:

use warnings;

sub soup
    my @components = qw(carrots leeks celeriac garlic onion);

    sub components
    return @components;

    sub mash_it
    @components = 'vegetable mash';


print('A soup made of ', join(', ', components()), ".\n");


print('Now, we just have ', components(), ".\n");

Since the two inner subroutine are created 'statically' at
compile-time, I wouldn't expect them to pick up new incarnations of
@components created at run time but they will continue to share the
initial one.

Re: Some sort questions - especially hashes

Quoted text here. Click to load it

We had that discussion just the other day. It's possible to avoid $a and
$b altogether by using a prototype, and IIRC it was no less efficient
that the globals when using a named sub for sorting rather than an
anonymous block.

Quoted text here. Click to load it

Did I suggest that? It doesn't sound like me... if I were maintaining
PL/Perl I would want to make that impossible. (I don't know if that can
be done without PPI.)

More generally, at least as of Pg 9 there's no need for nasty tricks
like this any more. PL/Perl now has configuration parameters which allow
you to run Perl code before 'require' is locked out of the interpreter,
so you can put sub definitions in a file and load them in a civilised

Quoted text here. Click to load it

You clearly understand how the lexical scoping of these subs works;
however, it's confusing enough that it's not surprising others don't,
and the warning is for their benefit. Even with a proper understanding
of the situation, you are left in the rather weird position that the
first invocation of soup() will share @components with the other subs,
while subsequent invocations will not, so the warning still probably
indicates you have done something wrong.

It's worth noting that the warning is not emitted for 'state' variables,
which (despite otherwise being ordinary lexicals) exist in only one
instance, so the sharing semantics make more sense.


Site Timeline