I wasn't clear from your post if portability was an issue. Your sample data lists *nix style file names but your point of reference is "Windows Explorer". If so, the answers given so far assume *nix file naming conventions and may not be portable. For portable solutions, you'll need to use File::Spec.
Here is an example showing how to use it. In addition to the sorting it also calculates the information needed to properly indent names "like Windows Explorer":
use strict; use warnings; use File::Spec; my @arr = ( { 'path' => '/c/', dir => '/' }, { 'path' => '/c/a1.mp3', 'file' => 1, 'dir' => '/c' }, { 'path' => '/c/a2.mp3', 'file' => 1, 'dir' => '/c' }, { 'path' => '/c/bb/aa1.mp3', 'file' => 1, 'dir' => '/c/bb' }, { 'path' => '/c/bb/aa2.mp3', 'file' => 1, 'dir' => '/c/bb' }, { 'path' => '/c/bb/', 'dir' => '/c' }, { 'path' => '/c/cc/', 'dir' => '/c' }, { 'path' => '/c/aa/', 'dir' => '/c' } ); my $TAB_WIDTH=3; my $FORMAT="%-30s%s\n"; #----------------------------------------- # The sorting function #----------------------------------------- sub parsePathPortably { my $hPathInfo = shift; my $sPath = $hPathInfo->{path}; my $bFile = $hPathInfo->{file}; my ($sVol, $sDir, $sLocal) = File::Spec->splitpath($sPath, !$bFile); # File::Spec->splitdir assumes $dir is a relative path # without this line the first element of @aDirs on *nix is # an empty directory (because nothing is before root) my $sRelPath = File::Spec->abs2rel($sDir, File::Spec->rootdir()); my @aDirs =File::Spec->splitdir($sRelPath); # get indentation level and local file name my $iDepth = scalar(@aDirs); unless ($bFile) { $iDepth--; $sLocal = pop @aDirs; } # reconstruct the path, but before each directory name # segment insert 0x000 and before each file name segment # insert 0x001. It is important to insert something # before *all* directory name elements to insure # that the "b" segment of /a/b/c and /a/b sort properly # # we also insert before file names on the off,off chance # that you run into a file system where there is a file # name that begins with 0x000. DOS and most *nix systems # prohibit 0x000 in file names, but not all # - see [Wikipedia://Filename] for a list of OS's where # 0x000 does not appear to be in the list of reserved or # prohibited characters, among them: OS2, various Mac OS's my $k = File::Spec->catpath ($sVol, File::Spec->catdir(map{ord(0).$_} @aDirs) , ord($bFile ? 1 : 0) . $sLocal); return $k => [ $iDepth, $sPath, $sLocal ]; } #-------------------------------------------------- # Demonstration of how to use the sorting function #-------------------------------------------------- my $hPaths = { map { parsePathPortably($_) } @arr }; foreach my $k (sort keys %$hPaths) { my ($iDepth, $sPath, $sLocal) = @{$hPaths->{$k}}; my $sIndent = ' ' x ($TAB_WIDTH*$iDepth); printf($FORMAT, "$sIndent$sLocal", $sPath); }
This produces the following output:
c /c/ aa /c/aa/ bb /c/bb/ aa1.mp3 /c/bb/aa1.mp3 aa2.mp3 /c/bb/aa2.mp3 cc /c/cc/ a1.mp3 /c/a1.mp3 a2.mp3 /c/a2.mp3
In reply to Re: sorting tree with folders on top
by ELISHEVA
in thread sorting tree with folders on top
by diweooy
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |