Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Perl > Perl Misc > sort function, in non-standard cases

Reply
Thread Tools

sort function, in non-standard cases

 
 
alexxx.magni@gmail.com
Guest
Posts: n/a
 
      06-26-2007
Hi everybody,
I need some hints on how to setup the sort function in a couple of
cases that happened to me recently

<disclaimer>I already did perldoc -f sort, yet I found mainly
discussed numerical/alphabetical cases</disclaimer>

The two sort problems I had - neither of which I was able to solve -
are the following:

1) given in @a a list of files/directories (e.g. returned by
File::Find), sort it directories first, then symlinks, then common
files.
The nearer I came was:

@a=sort {my $x= -d $a; my $y= -d $b; return $x
<=> $y} @a;

but it doesnt work.

2) sort @a, based on the existence/non-existence of the hash value
$c{$a}, where $a's are the elements of @a.

Both the problems are related to my difficulty of translating them in
some kind of comparison between two generic elements $a vs $b, as in
the typical $a<=>$b

Any hint is welcome!

Alessandro Magni

 
Reply With Quote
 
 
 
 
Joe Smith
Guest
Posts: n/a
 
      06-26-2007
http://www.velocityreviews.com/forums/(E-Mail Removed) wrote:
> Hi everybody,
> I need some hints on how to setup the sort function in a couple of
> cases that happened to me recently
>
> <disclaimer>I already did perldoc -f sort, yet I found mainly
> discussed numerical/alphabetical cases</disclaimer>


It is unfortunate that `perldoc -f sort` does not mention "Schwartzian Transform".
http://en.wikipedia.org/wiki/Schwartzian_transform

> sort it directories first, then symlinks, then common files.


#!/usr/bin/perl
# Purpose: Outputs directory listing, dirs first, then symlinks, then rest
use strict; use warnings;

push @ARGV,(glob '*') unless @ARGV;
my @typed_names =
map {substr $_,1}
sort
map { -l $_ ? "l$_" : -d $_ ? "d$_" : "r$_"}
@ARGV;
print join("\n",@typed_names),"\n";

-Joe
 
Reply With Quote
 
 
 
 
Joe Smith
Guest
Posts: n/a
 
      06-26-2007
Joe Smith wrote:

> #!/usr/bin/perl
> # Purpose: Outputs directory listing, dirs first, then symlinks, then rest
> use strict; use warnings;
>
> push @ARGV,(glob '*') unless @ARGV;
> my @typed_names =
> map {substr $_,1}
> sort
> map { -l $_ ? "l$_" : -d $_ ? "d$_" : "r$_"}
> @ARGV;
> print join("\n",@typed_names),"\n";


Another way:

sub sort_dir3 {
my %dir;
my @res;
foreach my $ent (@_) {
my $key = -l $ent ? 'Link' : -d $ent ? 'Directory' : 'Regular';
push @{$dir{$key}},$ent;
}
push @res, "\t\t$_\n",join("\n",sort @{$dir{$_}}),"\n\n" for sort keys %dir;
@res;
}

-Joe

P.S. The test for -l() before testing for -d() is deliberate. Unless you
want symlinks to directories to show up as directories instead of as symlinks.
 
Reply With Quote
 
anno4000@radom.zrz.tu-berlin.de
Guest
Posts: n/a
 
      06-26-2007
(E-Mail Removed) <(E-Mail Removed)> wrote in comp.lang.perl.misc:
> Hi everybody,
> I need some hints on how to setup the sort function in a couple of
> cases that happened to me recently
>
> <disclaimer>I already did perldoc -f sort, yet I found mainly
> discussed numerical/alphabetical cases</disclaimer>
>
> The two sort problems I had - neither of which I was able to solve -
> are the following:
>
> 1) given in @a a list of files/directories (e.g. returned by
> File::Find), sort it directories first, then symlinks, then common
> files.
> The nearer I came was:
>
> @a=sort {my $x= -d $a; my $y= -d $b; return $x
> <=> $y} @a;
>
> but it doesnt work.


That is a typical candidate for a Schwartz transform. To each file,
assign a rank of 0, 1, or 2 according as it is a directory, a symlink
or anything else. Then sort according to rank, breaking ties by
comparing the file names:

my @sorted_files = map $_->[ 0] =>
sort { $a->[ 1] <=> $b->[ 1] || $a->[ 0] cmp $b->[ 0] }
map {
my $rank = 2;
$rank = 0 if -d;
$rank = 1 if -l;
[ $_, $rank];
}
@files;

Anno
 
Reply With Quote
 
anno4000@radom.zrz.tu-berlin.de
Guest
Posts: n/a
 
      06-26-2007
Joe Smith <(E-Mail Removed)> wrote in comp.lang.perl.misc:
> (E-Mail Removed) wrote:
> > Hi everybody,
> > I need some hints on how to setup the sort function in a couple of
> > cases that happened to me recently
> >
> > <disclaimer>I already did perldoc -f sort, yet I found mainly
> > discussed numerical/alphabetical cases</disclaimer>

>
> It is unfortunate that `perldoc -f sort` does not mention "Schwartzian
> Transform".
> http://en.wikipedia.org/wiki/Schwartzian_transform
>
> > sort it directories first, then symlinks, then common files.

>
> #!/usr/bin/perl
> # Purpose: Outputs directory listing, dirs first, then symlinks, then rest
> use strict; use warnings;
>
> push @ARGV,(glob '*') unless @ARGV;
> my @typed_names =
> map {substr $_,1}
> sort
> map { -l $_ ? "l$_" : -d $_ ? "d$_" : "r$_"}
> @ARGV;
> print join("\n",@typed_names),"\n";


That's not strictly a Schwartz transform but a Guttman-Roesler
transform (GRT). A Schwartz transform builds a list of anonymous
arrays that hold the sort key(s) and the original elements and
uses a sort block to access the keys. A GRT (like your solution)
prepends a single sort key in string form and uses the default sort.

Anno
 
Reply With Quote
 
Michele Dondi
Guest
Posts: n/a
 
      06-26-2007
On Tue, 26 Jun 2007 01:39:30 -0700, Joe Smith <(E-Mail Removed)> wrote:

>my @typed_names =
> map {substr $_,1}
> sort
> map { -l $_ ? "l$_" : -d $_ ? "d$_" : "r$_"}
> @ARGV;


++ x 10**3! Strictly speaking this is not an ST, which you mention,
but even a GRT, which is better in many respcts. I would have gone ST,
but your solution is more compact, elegant, and most probably fast.
Best code contribution I've seen in some time! FYI, I'm reporting it
elsewhere...


Michele
--
{$_=pack'B8'x25,unpack'A8'x32,$a^=sub{pop^pop}->(map substr
(($a||=join'',map--$|x$_,(unpack'w',unpack'u','G^<R<Y]*YB='
..'KYU;*EVH[.FHF2W+#"\Z*5TI/ER<Z`S(G.DZZ9OX0Z')=~/./g)x2,$_,
256),7,249);s/[^\w,]/ /g;$ \=/^J/?$/:"\r";print,redo}#JAPH,
 
Reply With Quote
 
Tad McClellan
Guest
Posts: n/a
 
      06-26-2007
Joe Smith <(E-Mail Removed)> wrote:

> It is unfortunate that `perldoc -f sort` does not mention "Schwartzian Transform".



But `perldoc -q sort` does.


--
Tad McClellan
email: perl -le "print scalar reverse qq/moc.noitatibaher\100cmdat/"
 
Reply With Quote
 
Michele Dondi
Guest
Posts: n/a
 
      06-26-2007
On Tue, 26 Jun 2007 12:12:01 +0200, Michele Dondi
<(E-Mail Removed)> wrote:

>Best code contribution I've seen in some time! FYI, I'm reporting it
>elsewhere...


Done: <http://perlmonks.org/?node_id=623356>.


Michele
--
{$_=pack'B8'x25,unpack'A8'x32,$a^=sub{pop^pop}->(map substr
(($a||=join'',map--$|x$_,(unpack'w',unpack'u','G^<R<Y]*YB='
..'KYU;*EVH[.FHF2W+#"\Z*5TI/ER<Z`S(G.DZZ9OX0Z')=~/./g)x2,$_,
256),7,249);s/[^\w,]/ /g;$ \=/^J/?$/:"\r";print,redo}#JAPH,
 
Reply With Quote
 
John W. Krahn
Guest
Posts: n/a
 
      06-26-2007
Joe Smith wrote:
> (E-Mail Removed) wrote:
>> I need some hints on how to setup the sort function in a couple of
>> cases that happened to me recently
>>
>> sort it directories first, then symlinks, then common files.

>
> #!/usr/bin/perl
> # Purpose: Outputs directory listing, dirs first, then symlinks, then rest
> use strict; use warnings;
>
> push @ARGV,(glob '*') unless @ARGV;
> my @typed_names =
> map {substr $_,1}
> sort
> map { -l $_ ? "l$_" : -d $_ ? "d$_" : "r$_"}
> @ARGV;
> print join("\n",@typed_names),"\n";


You only need to stat the files once:

my @typed_names =
map {substr $_,1}
sort
map { -l $_ ? "l$_" : -d _ ? "d$_" : "r$_"}
@ARGV;



John
--
Perl isn't a toolbox, but a small machine shop where you
can special-order certain sorts of tools at low cost and
in short order. -- Larry Wall
 
Reply With Quote
 
John W. Krahn
Guest
Posts: n/a
 
      06-26-2007
http://www.velocityreviews.com/forums/(E-Mail Removed)-berlin.de wrote:
>
> That is a typical candidate for a Schwartz transform. To each file,
> assign a rank of 0, 1, or 2 according as it is a directory, a symlink
> or anything else. Then sort according to rank, breaking ties by
> comparing the file names:
>
> my @sorted_files = map $_->[ 0] =>
> sort { $a->[ 1] <=> $b->[ 1] || $a->[ 0] cmp $b->[ 0] }
> map {
> my $rank = 2;
> $rank = 0 if -d;
> $rank = 1 if -l;
> [ $_, $rank];
> }
> @files;


You only need to stat the files once:

my @sorted_files = map $_->[ 0] =>
sort { $a->[ 1] <=> $b->[ 1] || $a->[ 0] cmp $b->[ 0] }
map {
my $rank = 2;
$rank = 0 if -d;
$rank = 1 if -l _;
[ $_, $rank];
}
@files;



John
--
Perl isn't a toolbox, but a small machine shop where you
can special-order certain sorts of tools at low cost and
in short order. -- Larry Wall
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: unittest - sort cases to be run Terry Reedy Python 2 08-21-2012 05:27 PM
Connecting multiple test cases in a sort of pipe Raghuram Devarakonda Python 2 07-30-2009 02:59 PM
What's the ruby way to sort string with cases in mind Sam Kong Ruby 10 09-20-2006 03:39 PM
Home server cases and external firewire cases thingy@nowhere.commy NZ Computing 5 03-14-2006 07:56 AM
Ado sort error-Ado Sort -Relate, Compute By, or Sort operations cannot be done on column(s) whose key length is unknown or exceeds 10 KB. Navin ASP General 1 09-09-2003 07:16 AM



Advertisments