why doesn't sort properly?

U

Uri Guttman

AS> Just for fun, I tried this:

AS> my ( $ar, $br) = $order ? \ ( $a, $b) : \ ( $b, $a);
AS> my @sorted = sort { $$ar <=> $$br } @line;

AS> but in the sort block $$ar and $$br come up undefined. I don't quite
AS> understand that. It must be something about the way $a and $b are
AS> aliased to the list elements.

the sort block is passed $a and $b, they are not just set globally
before it is called. they are implicit params with fixed names and it
was done for speed.

and now it is time to plug Sort::Maker which would have made short
shrift of this whole thread. :)

uri
 
U

Uri Guttman

AS> Ah, yes, that works:

AS> my ( $ag, $bg) = $order? ( *a, *b) : ( *b, *a);
AS> my @sorted = sort { $$ag <=> $$bg } @line;

why not do it at a higher level?

my $sorter = $order ?
sub { sort { $a <=> $b } @_ } :
sub { sort { $b <=> $a } @_ } ;

my @ordered = $sorter->( @unordered ) ;

of course adjust those to use ->[6] or whatever. note that those subs
are compiled once so the only overhead is selecting which one. there is
some extra overhead in passing @_ but the logic is clean and that makes
up for any slowdown.

trying to mess with the sort block itself is painful. it is better to
write higher level sort subs that do the job and to select which one you
want.

uri
 
U

Uri Guttman

f> if I sort them replacing the if block

f> if( $order == 1 ) {
f> @lines = sort { $a->[6] <=> $b->[6] };
f> } else {
f> @lines = sort { $b->[6] <=> $a->[6] };
f> }

why can't you just do that?

f> with

f> @lines = sort { $a->[6] <=> $b->[6] };

f> the routine works fine. But I want to choose ascending/descending.

you have working code above? $order chooses ascending/descending.

or see my recent post showing another way to do this. your requirement
for shorter code isn't doing you any good. just get it working or use
the working code you have been given.

uri
 
A

Anno Siegel

Uri Guttman said:
AS> Ah, yes, that works:

AS> my ( $ag, $bg) = $order? ( *a, *b) : ( *b, *a);
AS> my @sorted = sort { $$ag <=> $$bg } @line;

why not do it at a higher level?

my $sorter = $order ?
sub { sort { $a <=> $b } @_ } :
sub { sort { $b <=> $a } @_ } ;

my @ordered = $sorter->( @unordered ) ;

Oh, sure. One could go a step further and use one of our beloved dispatch
tables (an array, not a hash this time around):

my @sorter = (
sub { sort { $b <=> $a } @_ },
sub { sort { $a <=> $b } @_ },
sub { sort { $a cmp $b } @_ },
# etc.
);

my @ordered = $sorter[ $order]->( @unordered);
of course adjust those to use ->[6] or whatever. note that those subs
are compiled once so the only overhead is selecting which one. there is
some extra overhead in passing @_ but the logic is clean and that makes
up for any slowdown.

Again, it's only linear, and sort is worse than linear. For long lists
the overhead won't matter. For short lists, it won't matter either :)
trying to mess with the sort block itself is painful. it is better to
write higher level sort subs that do the job and to select which one you
want.

Yeah. As demonstrated by this example. I saw two scalars that needed to
be swapped in one situation and not in another, so I thought of scalar
refs. The naive solution

sort { $$ar <=> $$br }, @unordered;

doesn't work with real refs to $a and $b. It would be neat enough, and
probably well known, if it did. Pursuing it took us to globs and symrefs.
What a mess.

Anno
 
U

Uri Guttman

AS> Oh, sure. One could go a step further and use one of our beloved dispatch
AS> tables (an array, not a hash this time around):

AS> my @sorter = (
AS> sub { sort { $b <=> $a } @_ },
AS> sub { sort { $a <=> $b } @_ },
AS> sub { sort { $a cmp $b } @_ },
AS> # etc.
AS> );

better to make that a hash keyed on the sort name.

and you can do the same with the sort block itself since you can declare
named subs for each sort block. i am not sure if you can use code refs
directly without the surrounding {} as you can with named sort
blocks. then you could do:

my $cmp_block = $cmp_blocks{ $sort_type } ;
@ordered = sort $cmp_block @unordered ;

compare blocks would be subs that work on $a and $b

you could do this which i think works

@ordered = sort { &$cmp_block } @unordered ;

but that could add some overhead for each compare call. but it does make
for nice code.

AS> sort { $$ar <=> $$br }, @unordered;

AS> doesn't work with real refs to $a and $b. It would be neat enough, and
AS> probably well known, if it did. Pursuing it took us to globs and symrefs.
AS> What a mess.

that has never worked as $a and $b are passed as if they were in
local(). this does mean you can do the sort block stuff i showed above
but you can't reference then before the sort is called. the
symref/typeglob stuff works because they will still see the proper
global $a/$b after they are localized.

perl6 will have a sort api that is much like sort::maker (because damian
helped me with that module's api and he wrote the api for the perl6
sort) so the $a/$b business and the duplication of the extraction code
will be long gone.

uri
 
X

Xicheng

Thanks Xicheng for your proposal, the problem is that the numbers $k
are not unique, if I use them as keys for an hash I lose data.

fields #6 are numbers like that:

34.104
34.646
24.124
17.136
16.876
20.432
20.455
34.05

if I sort them replacing the if block

if( $order == 1 ) {
@lines = sort { $a->[6] <=> $b->[6] };
} else {
@lines = sort { $b->[6] <=> $a->[6] };
}

with

@lines = sort { $a->[6] <=> $b->[6] };

the routine works fine. But I want to choose ascending/descending.
If you can change $order to (-1,1), like 1=>ASC, -1=>DSC, then you can
do it faster:
by using array of (1*2)arrays and simple sorting.... I used $flag to
indicate the $order in your code..
=============================
use warnings;
use strict;
my @arr=();
my $flag = -1;
# $flag can be either positive or negative number to refer to ASC or
DSC sorting.
open my $fh, "< my_record.csv" or die "can't open my_record.csv: $!";
while(<$fh>) {
push @arr, [$flag*(split/;/)[6], $_];
}
print map $_->[1], sort{$a->[0] <=> $b->[0]} @arr;
===================================
HTH,
Xicheng
 
F

filippo2991

thanks guys for your support!
I have to say, I must study globs.

Back to my problem:
the fact is that the code I used doesn't work properly: it sorts always
ascending regardless of the condition. I'm sure the two condition are
met, because I used a standard output print command into each
condition.
The strange thing is that the behaviour change changing the position of
the routine in the file. I spent days debugging, no results. After
studiyng globs I'll use one of your solutions.

Thanks again,

Filippo
 
P

Paul Lalli

thanks guys for your support!

Who are you thanking? Please quote some context when you post a reply!
I have to say, I must study globs.

Back to my problem:
the fact is that the code I used doesn't work properly: it sorts always
ascending regardless of the condition. I'm sure the two condition are
met, because I used a standard output print command into each
condition.

Is this the same code as before, that you were told to enable strict
and warnings? Did you do that? Did you see the "subroutine redefined
at..." warnings?
The strange thing is that the behaviour change changing the position of
the routine in the file.

Not strange at all. Subroutines are defined at compile time. If you
list the same subroutine a second time, it wipes out the definition of
the first subroutine. You only had ONE definition of the subroutine,
regardless of how many you typed.
I spent days debugging, no results.

You spent days debugging, and either didn't enable warnings, or didn't
find out what the warning meant?

If I've mis-guessed at your continued problem, please post a
short-but-complete script that demonstrates your current issue.

Paul Lalli
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,132
Latest member
TeresaWcq1
Top