use strict; use warnings; use Data::Dumper; my $last_hour = 23; my %best_of; while () { my ( $quote, $time ) = m{ \A # beginning of line ( [^,]+ ) # non-commas \s* , \s* # comma with optional spaces ( # open capture \d\d? # hours : \d\d # minutes : \d\d # seconds ) }xms; my ( $hour, $min, $sec ) = split /:/, $time; if ( '00' eq $sec && '00' eq $min && -1 == --$hour ) { $hour = $last_hour; } my $seconds_past = $min * 60 + $sec; if ( ! $seconds_past || $best_of{ $hour }{second} < $seconds_past ) { $best_of{ $hour } = { second => $seconds_past, time => $time, quote => $quote, }; } } print Dumper \%best_of; __DATA__ 1.53311 ,1:59:52 1.53311 ,1:59:5220 1.53311 ,1:59:52 1.53311 ,1:59:52hi 1.53311 ,2:00:00 1.53306 ,2:00:03 1.53307 ,2:00:06 #### $VAR1 = { '1' => { 'quote' => '1.53311 ', 'time' => '2:00:00', 'second' => 0 }, '2' => { 'quote' => '1.53307 ', 'time' => '2:00:06', 'second' => 6 } };