http://www.perlmonks.org?node_id=487299

malaga has asked for the wisdom of the Perl Monks concerning the following question:

I can't get this sort - not sure if it's because i'm mixing up array/hash, or if i'm just mixed up period:
#filenames looks like this: category_Title Words_1 #SEARCH THROUGH THE CONTENT DIRECTORY AND FIND THE FILES THAT MATCH chdir("$contentdir");#change to the content directory my $stuff = ".";#make it $_ opendir THISDIR, "$stuff";#open the content directory my @submenu = readdir THISDIR;#put the names of the files in an array closedir THISDIR; ($sub1, $sub2, $sub3) = split (/\_/, $_,3);#split it on the underscore +s $sub3 = sort { $b <=> $a } $sub3;
doesn't work. i've also tried:
my @newarray = ($sub1,$sub2,$sub3); @newarray = sort { $a->[2] cmp $b->[2] } @newarray;
and a million other wrong ways. please advise. thank you!
Malaga

Replies are listed 'Best First'.
Re: Sort - can't
by QM (Parson) on Aug 29, 2005 at 00:10 UTC
    Make that
    chdir("$contentdir") or die "Couldn't chdir ..., "; opendir THISDIR, '.' or die "Couldn't opendir ..., "; my @submenu = readdir THISDIR or die "Nothing to readdir, "; close THISDIR; # really need a die here too :)
    Then you got lost. You tried this:
    ($sub1, $sub2, $sub3) = split (/\_/, $_,3);
    Except that $_ wasn't set by anything yet. Your directories are in @submenu, and split only works on one scalar (at a time).

    Moreover, sort is redundant on scalars:

    $sub3 = sort { $b <=> $a } $sub3;

    Somehow you need to pick which of the @submenu entries you want to split (or perhaps all?), and then what it is you're sorting...

    -QM
    --
    Quantum Mechanics: The dreams stuff is made of

Re: Sort - can't
by lidden (Curate) on Aug 29, 2005 at 00:16 UTC
    I think you are mixed up :-)

    You should turn on strict and warnings
    use strict; use warnings;
    They will give you hints.
    You split $_ but you are not setting it. You also say you want to find files that match, match what? There is no need to quote variables like you do, and you should check so that your opendir worked.
    opendir THISDIR, $stuff or die "Noo $!"; #open the content director +y
Re: Sort - can't
by tlm (Prior) on Aug 29, 2005 at 00:07 UTC

    Let's start with the basics: what on earth do you want to do?

    the lowliest monk

Re: Sort - can't
by pg (Canon) on Aug 29, 2005 at 00:13 UTC

    $_ is not even initialized, what are you spliting?

    Why other people can realize this when you cannot, is there any magic? No magic at all, just "use warnings".

Re: Sort - can't
by chas (Priest) on Aug 29, 2005 at 00:14 UTC
    I don't see that you've set $_ to anything...
    chas
Re: Sort - can't
by malaga (Pilgrim) on Aug 29, 2005 at 01:09 UTC
    sorry - i was abbreviating. the only place i'm having a problem is in the sorting. so, let me start over:
    array looks like this: category_Title Words_1 category_Title Words_2 category_Title Words_3 category_Title Words_4 ($sub1, $sub2, $sub3) = split (/\_/, @array,3); $sub3 = sort { $b <=> $a } $sub3; doesn't work. i've also tried: my @newarray = ($sub1,$sub2,$sub3); @newarray = sort { $a->[2] cmp $b->[2] } @newarray;
    Malaga
      You've failed again to ask your question appropriately.

      First the diagnoses:

      ($sub1, $sub2, $sub3) = split (/\_/, @array,3);
      split doesn't work on an array!!!
      while my $elem (@array) { ($sub1,$sub2,$sub3) = split(/_/, $elem, 3); # do something here... }
      Now you might have something in $sub3, but this doesn't make any sense either:
      $sub3 = sort { $b <=> $a } $sub3;
      You can't sort a scalar (well, it doesn't do anything interesting)

      Seems what you really want to do is sort the elements of @array by the last field (numerically), in which case you'll need something like this:

      my @a2; while my $elem (@array) { my @fields = split(/_/, $elem, 3); push @a2, \@fields; } my @a3 = sort { $b->[2] <=> $a->[2]} @a2;
      But you should really see How (Not) to Ask a Question.

      -QM
      --
      Quantum Mechanics: The dreams stuff is made of

      I think that you are actually having trouble with spliting, not so much with the sorting. split acts on a scalar at a time. I'm guessing that you want something more like this:

      my @split_arr = map { [ split /_/, $_, 3 ] } @array; my @sorted = sort { $a->[2] <=> $b->[2] } @split_arr;

      Or more verbosely:

      my @split_arr; for ( @array ) { my @split_elem = split /_/, $_, 3; push @split_arr, \@split_elem; } my @sorted = sort { $a->[2] <=> $b->[2] } @split_arr;

      Update: changed my guess at what you want from string sort to numeric sort.

      assuming you want to sort by category/title/number

      #!/usr/bin/perl -w use strict; my @array = qw (biology_humananatomy_2 math_riemannhypothesis_1 biolog +y_humananatomy_1 ); my @AoA; for (@array) { push(@AoA,[split /\_/,$_,3]); } my @final = sort {$a->[0] cmp $b->[0] || $a->[1] cmp $b->[1] || $a->[2] <=> $b->[2]} @AoA; for (@final) { print join('_',@$_),$/; }

      output:

      biology_humananatomy_1 biology_humananatomy_2 math_riemannhypothesis_1

      Please read other posts to understand why your code does not work.

      cheers

      SK

      "($sub1, $sub2, $sub3) = split (/\_/, @array,3); $sub3 = sort { $b <=> $a } $sub3;"

      It isn't clear to me what your array is exactly, but in any case, as has been remarked already, $sub3 will be a single string, and sorting it will have no effect. It isn't clear to me what you want to do or I would have offered more suggestions.
      chas
      (Update: Actually, what I said is misleading. I *think* the first line of the code above will take @array in scalar context giving the number of elements, and then $sub1 will be this value; $sub2 and $sub3 will be empty. The sorting will do nothing useful, of course. So perhaps you should just ignore my reply above and read the other replies...)

      Sort what by what?

      Your code is too way off for me to decipher your intentions.

      If you want to sort the filenames by the substring after the last _, then I'd do something like

      my @sorted = map $_->[ 0 ], sort { $a->[ 1 ] cmp $b->[ 1 ] } map [ $_, ( split '_' )[ -1 ] ], @unsorted;
      (untested).

      the lowliest monk

      thanks everybody. i get it now and fixed it. I did know I was doing it all wrong of course, that's why i posted. For some reason I couldn't see where the scalars and arrays were in this. everything was working till i had to add the sort - i wasn't able to back out and see where changes had to be made. i appreciate the help. hopefully people learn from my dumb posts.
      #SEARCH THROUGH THE CONTENT DIRECTORY AND FIND THE FILES THAT MATCH chdir("$contentdir");#change to the content directory my $stuff = ".";#make it $_ opendir THISDIR, "$stuff";#open the content directory my @submenu = readdir THISDIR;#put the names of the files in an array closedir THISDIR; for (1..2) {shift @submenu;} my @aaa; for (@submenu) { push(@aaa,[split /\_/,$_,3]); } my @final = sort {$a->[2] <=> $b->[2] } @aaa; for (@final) { my $cat=$_->[0]; my $title=$_->[1]; my $rankk=$_->[2]; (my $rank, $tossit) = split (/\./, $rankk,2); #foreach submenu item print it if ($cat=~$main) { $counter++; if ($counter > 1) { print "<a href \= \"/cgi-bin/idx.pl?$sub1$sep$sub2$sep$sub3\">"; print "$sub2"; print "</a>"; etc., etc. i know this isn't pretty, but it is what it is.
      Malaga
        For some reason I couldn't see where the scalars and arrays were in this.
        Here's a tool you already have to help you with this: Perl debugger!

        Use the x command to see what a variable holds. It shows you the complete structure as if it were an array at the top level. (So hashes show up better if you escape the percent sign, as in the first example below).

        c:\perl\perl>perl -de 0 Loading DB routines from perl5db.pl version 1.28 Editor support available. Enter h or `h h' for help, or `perldoc perldebug' for more help. main::(-e:1): 0 DB<1> %x = ( 123, [ qw(one two three) ], 456, [ qw(four five six) ], + 789, [ qw(seven eight nine) ] ) DB<2> x \%x 0 HASH(0x1d6c490) 123 => ARRAY(0x15d52a4) 0 'one' 1 'two' 2 'three' 456 => ARRAY(0x1d6c628) 0 'four' 1 'five' 2 'six' 789 => ARRAY(0x1d6c664) 0 'seven' 1 'eight' 2 'nine' DB<3> @x = ( { 1, "one", 2, "two", 3, "three" }, { 4, "four", 5, "fi +ve", 6, "six" }, { 7, "seven", 8, "eight", 9, "nine" } ) DB<4> x @x 0 HASH(0x1d70b24) 1 => 'one' 2 => 'two' 3 => 'three' 1 HASH(0x1d97a78) 4 => 'four' 5 => 'five' 6 => 'six' 2 HASH(0x1d97ab4) 7 => 'seven' 8 => 'eight' 9 => 'nine' DB<5>

        -QM
        --
        Quantum Mechanics: The dreams stuff is made of

Re: Sort - can't
by Codon (Friar) on Aug 29, 2005 at 18:40 UTC
    From what I can gather from your post, you are trying to sort a list of files in a directory based on the last element of the filename. Your code, and therefore intent, is not clear. Try this:

    my @new_array = sort { $b->[2] <=> $a->[2] } map { [ split /\//, $_, 3 + ] } @submenu;
    This will take your items in @submenu, split them all into three elements, then do a NUMERIC sort in descending order on the last element and put the results into @new_array. Please note that @new_array will be the unsplit @submenu. If you want split, the above algorithm will need to be broken down into intermediate steps. Also note, if you do not want a numeric sort, change <=> to cmp to get an ALPHA sort.

    Ivan Heffner
    Sr. Software Engineer, DAS Lead
    WhitePages.com, Inc.