my @res = analyze(); for (@res) { print $_->{f1} . ',' . $_->{f2} . ',' . $_->{f3} . "\n"; } sub analyze { # get the data as an array of hashes just like DBI would return my @data = map { chomp; split /,/; { f1 => $_[0], f2 => $_[1], f3 => $_[2] } } ; # arrays for holding bits of results my (@res_red, @res_blu, @res_wht, @nxt_res_red, @nxt_res_blu, @nxt_res_wht ); # counters for tracking whether we are before or # after the 'Red' divide my $i = -1; my $j; # array to hold rows *before* the 'Red' divide my @seen; LOOP: for (@data) { if ($i >= 0) { if ($_->{f2} eq 'White') { next LOOP if $j > 3; push @nxt_res_wht, $_; $j++; } if ($_->{f2} eq 'Blue') { push @nxt_res_wht, $_; last LOOP; } } else { if ($_->{f2} eq 'Red') { push @res_red, $_; $i++; my @rev_seen = reverse @seen; my $k; REV_WHITE: for (@rev_seen) { if ($_->{f2} eq 'White') { push @res_wht, $_; $k++ } last REV_WHITE if $k > 3; } REV_BLUE: for (@rev_seen) { if ($_->{f2} eq 'Blue') { push @res_blu, $_; last REV_BLUE; } } push @res_blu, reverse(@res_wht), @res_red; } else { push @seen, $_; } } } push @res_blu, @nxt_res_wht, @nxt_res_red; return @res_blu; } __DATA__ 1.00,Blue,12:00 40.20,White,12:00 80.30,White,12:00 120.00,White,12:00 126.00,White,12:00 162.43,White,12:00 198.86,White,12:00 235.29,White,12:00 271.72,Red,03:45 308.15,White,12:00 344.58,White,12:00 381.01,White,12:00 417.44,White,12:00 453.87,White,12:00 490.30,White,12:00 526.73,White,12:00 563.16,Red,07:45 599.59,White,12:00 636.02,White,12:00 672.45,White,12:00 708.88,White,12:00 745.31,White,12:00 781.74,White,12:00 818.17,White,12:00 854.60,Blue,12:00 891.03,White,12:00 963.89,White,12:00 1000.32,White,12:00 1036.75,Red,08:30 1073.18,White,12:00 1109.61,Red,06:00 1146.04,White,12:00 1182.47,White,12:00 1218.90,White,12:00 18516.40,Blue,12:00 1255.33,White,12:00 927.46,White,12:00