Finding the file name with maximum numeric suffix

180 views Asked by At

I have a list of files with mmddyyyy_nnnnn format. How do I find file with the highest number in postfix nnnnn using perl?

Example: for these three files

11232014_00001
11232014_00002
11232014_00003

I want to return file name for 00003.

4

There are 4 answers

0
Miller On

Since you dealing with fixed width filenames, I'd suggest reformatting and sorting by alpha:

use strict;
use warnings;

my @files = qw(11232014_00001 11242014_00002 11232015_00003);

my @sorted = sort {
    local ( $a, $b ) = map { s/(\d{2})(\d{2})(\d{4})/$3$1$2/r or die "Invalid format: $_" } ( $a, $b );
    $a cmp $b;
} @files;

print "$sorted[-1]";

Outputs:

11232015_00003
0
mpapec On

Full sort as in ST is not efficient for larger lists when only looking for maximal value, thus reduce from List::Util core module might be optimal solution,

use List::Util 'reduce';

my @files = qw(11232014_00001 11242013_00002 11232012_00003);
my ($max) = reduce {
    my ($aa, $bb) = map /(\d+)$/, $a,$b;
    $aa > $bb ? $a : $b
  }
  @files;

Similar approach by using max_by from List::UtilsBy

use List::UtilsBy 'max_by';

my @files = qw(11232014_00001 11242013_00002 11232012_00003);
my $max = max_by { ( /(\d+)$/ )[0] } @files;
0
Toto On

I'd use a Schwartzian transform:

#!/usr/bin/perl
use Modern::Perl;

my @files = qw(11232014_00001 11242013_00002 11232012_00003);
my ($highest)= 
    map { $_->[0] }
     sort { $b->[1] <=> $a->[1] }
      map { [$_, /(\d+)$/] }
       @files;
say $highest;

Output:

11232012_00003
0
afenster On

I hate using sort for obviously linear algorithm (you don't actually need to sort your list, you only want to find a maximum), so here is a solution using good old foreach loop and no sorting at all:

use strict;
use Modern::Perl;

my @files = qw(11232014_00001 11242013_00002 11232012_00003 22222222_00001);
my ($max_value, $max);
foreach (@files) {
        if (/_(\d+)$/ && (!defined $max_value || $1 > $max_value)) {
                $max_value = $1;
                $max = $_;
        }
}
say $max;