Re: Advanced Sorting
by turnstep (Parson) on Apr 20, 2000 at 01:59 UTC
|
It's hard to see what you are asking. If you are trying to sort
by name and then age, your solution does not quite work. Here's
some code to do that:
@sorted = sort {
unless ($a->{'name'} cmp $b->{'name'}) {
$a->{age} <=> $b->{age}
}
} @data;
I used the following list:
jim 18
bob 24
bob 14
cathy 98
cathy 45
Which gets sorted to:
bob 14
bob 24
cathy 45
cathy 98
jim 18
| [reply] [d/l] [select] |
|
|
Thanks for the reply, but that's not quite what I need. I need to sort on values that may be all strings OR all numbers, not a primary then secondary search. And one small optimization to your code would be:
@sorted = sort {
<BR>
$a->{'name'} cmp $b->{'name'} || $a->{age} <=> $b->{age}
<BR>
} @data;
<BR>
Perl's sorting algorithm will return '0' if the "cmp" is equal, defaulting to the secondary sort.
| [reply] [d/l] |
Re: Advanced Sorting
by snowcrash (Friar) on Apr 20, 2000 at 12:43 UTC
|
just another one that might speed up sorting if the sort
criteria would get more complicated...
my @sorted = map { $_->[2] }
sort { ($a->[0] cmp $b->[0]) || ($a->[1] cmp $b->[1]) }
map { [ $_->{name}, $_->{age}, $_ ] }
@data;
| [reply] [d/l] |
Re: Advanced Sorting
by btrott (Parson) on Apr 20, 2000 at 02:41 UTC
|
You could try something like this, though I'm not sure
it's not uglier than what you have. :) Although this doesn't
have a conditional in the sort-block, so it should be
faster, I think.
my $field = "name";
sub numsort { $a->{$field} <=> $b->{$field} }
sub alphasort { $a->{$field} cmp $b->{$field} }
my @data = (
{ name => 'jim', age => 16 },
{ name => 'bob', age => 18 },
);
my $sortsub = $field eq "name" ? 'alphasort' : 'numsort';
my @sorted;
{
no strict 'refs';
@sorted = sort $sortsub @data;
}
You need the "no strict 'refs'" because that
sort $sortsub @data
is actually using symbolic references, which is ugliness
itself. :)
Can sort subs be sub references? From the docs I looked at,
it doesn't seem like they can. If they could, that would
be a *much* cleaner way of doing it. | [reply] [d/l] [select] |
|
|
#!/usr/bin/perl -w
use strict;
my @data = (
{ name => 'jim', age => 16 },
{ name => 'bob', age => 18 },
);
sub sort_me {
my $field = shift;
if ($field eq "name") {
return sub { $a->{$field} cmp $b->{$field} };
} else {
return sub { $a->{$field} <=> $b->{$field} };
}
}
my @sorted;
my $type = sort_me("name");
@sorted = sort $type @data;
$type = sort_me("age");
@sorted = sort $type @data;
Closures are so nice. | [reply] [d/l] |
RE: Advanced Sorting
by dsdisc (Initiate) on Apr 20, 2000 at 04:04 UTC
|
Thanks turnstep, btrott and chromatic!! Now it might get more complicated, or at least messy if I had multiple keys in the hashes, some of which were strings and some of which were numbers. Like in addition to age and name if I had Last Name (string), salary (number), car (string), model year (number), etc. Then I would have to test for every one. That's why I used a reg exp in the first place. But I like the idea of testing outside of the sort for efficiency, I will definitely use that. | [reply] |
|
|
You could use a regex to test for appropriate key names. Or you could do some testing with my technique (returning an anonymous sub) and change the test to see if the datatype is a number if you take a look at How to identify a number datatype in a string?. It's probably lots simpler just to keep a data structure of appropriate fields guaranteed to hold strings or numbers, though.
| [reply] |
Re: Advanced Sorting
by turnstep (Parson) on Apr 20, 2000 at 02:37 UTC
|
In that case, the only optimization to your code I can think
of is:
if ($field eq "name") {
$a->{$field} cmp $b->{$field}
}
else {
$a->{$field} <=> $b->{$field}
}
which stops the code from examining every value twice,
but simply evaluates a scalar. It benchmarks as slightly
faster. Actually, for ultimate speed, move the field check
before the sort subroutine is called:
if ($field eq "name") { @sorted = sort @data; }
else { @sorted = sort {$a <=> $b} @data; }
etc...
| [reply] [d/l] [select] |
|
|
I am just getting into perl,and have a basic simple question. I have written a script that reads in a directory of logfiles, sorts them in reverse chronological order, and outputs them into an html page.
I cannot figure out how to sort the directory deeper than just the month, which comes first (the files in the dir are all listed by month/day/year). How can I sort this so the most recent days are first?
| [reply] |
|
|
1. read the perlman (or unixman) for the commands stat() and sort()
2. try to understand the following :-)
sub bydate{(stat $dir.$a)[9]<=>(stat $dir.$b)[9];}
@sortedfiles = sort bydate @files_in_your_dir;
Have a nice day
All decision is left to your taste
Update
ok, I might have been wrong when assuming that logs get analyzed but not changed, after they have been archived
| [reply] [d/l] |
|
|
|
|