in reply to Sorting files by 3 numbers in the name

# These constants make the code below more readable. # use constant { IX_FILENAME => 0, IX_RUN => 1, IX_DISTRICT => 2, IX_COPY => 3, IX_TOTAL => 4, }; # Read this bit from bottom to top: # my @sorted = # Now we've sorted our arrayrefs by the fields we're interested in # we loop through them again, pulling out just the filename and # discarding the other parts. map { $_->[IX_FILENAME] } # Sort by the fields we're interested in. Note that if the two # values for RUN are different, this will sort by them, and everyt +hing # following the first 'or' is ignored. If they're the same, that # comparison returns 0, so the stuff after 'or' isn't ignored, # and we compare by DISTRICT, then COPY, then TOTAL. sort { $a->[IX_RUN] <=> $b->[IX_RUN] or $a->[IX_DISTRICT] <=> $b->[IX_DISTRICT] or $a->[IX_COPY] <=> $b->[IX_COPY] or $a->[IX_TOTAL] <=> $b->[IX_TOTAL] } # For each filename, split it into an arrayref, so that the first # element in the arrayref is the filename itself, and the rest are # the fields we're interested in. map { [ $_, m/\A[A-Z0-9]+_([0-9])+_ETSTexas_.*_Candidate_RRD_([0-9]+ +)_([0-9]{2})_([0-9]{2})/i ] } # Take our list of filenames… @files; # Check it works. (It does.) # print Dumper(\@sorted);

Replies are listed 'Best First'.
Re^2: Sorting files by 3 numbers in the name
by LanX (Saint) on May 26, 2017 at 14:21 UTC

      Yeah, but I think they were added in 5.10, and when possible I try to give examples using 5.8 features. (Something like say is excusable, because it's so easy to write a shim for it.

      sub say { local $\ = "\n"; print(@_ or $_) } sub IO::Handle::say { my $h = shift; local $\ = "\n"; $h->print(@_ or +$_) }

      I also quite like this way:

      use constant { IX_FILENAME => 0, IX_RUN => 2, IX_DISTRICT => 8, IX_COPY => 9, IX_TOTAL => 10, }; print Dumper map { Dumper($_), $_->[IX_FILENAME] } sort { $a->[IX_RUN] <=> $b->[IX_RUN] or $a->[IX_DISTRICT] <=> $b->[IX_DISTRICT] or $a->[IX_COPY] <=> $b->[IX_COPY] or $a->[IX_TOTAL] <=> $b->[IX_TOTAL] } map { [ $_, split /_/ ] } @files;
        agreed, with split it's a plus! =)

        I wonder about the best idiomatic way ( with or w/o List::Util ) to shorten the or chain such that we don't need to repeat the field names.

        use strict; use warnings; use Data::Dump; use List::Util qw/first/; $\="\n"; # --- init my @fields = qw( RUN DISTRICT COPY TOTAL ); my %a = map { $_ => 1- int rand 3 } @fields; my %b = map { $_ => 1- int rand 3 } @fields; dd \@fields,\%a,\%b; # --- w/o List::Util my $last; my $field; for (@fields) { $field =$_; $last = $a{$_} <=> $b{$_} and last; } print "$field,$last"; # --- with List::Util print first { $last = $a{$_} <=> $b{$_} } @fields; print $last;

        ( ["RUN", "DISTRICT", "COPY", "TOTAL"], { COPY => -1, DISTRICT => 1, RUN => 1, TOTAL => -1 }, { COPY => -1, DISTRICT => 1, RUN => 1, TOTAL => 0 }, ) TOTAL,-1 TOTAL -1

        Cheers Rolf
        (addicted to the Perl Programming Language and ☆☆☆☆ :)
        Je suis Charlie!