use strict; use warnings; use 5.010; use List::MoreUtils qw(uniq); my @data; while () { my %row; @row{qw(employee form date)} = split /\s+/; push @data, \%row; } my @employees = uniq sort map { $_->{employee} } @data; for my $employee (@employees) { say $employee; my @signed = sort { $a->[0] <=> $b->[0] } map { [ $_->{form}, $_->{date} ] } grep { $_->{employee} == $employee } @data; for (@signed) { printf "\t%s\t%s\n", @$_; } } __DATA__ 10001 10 20090101 10002 10 20080515 10003 10 20090323 10001 20 20090412 10002 20 20090711