Assuming your example contains some typos, you may want to go for:
use 5.010;
use strict;
use warnings;
use List::Util 'max';
my (%data, %all, @keys);
while (<DATA>) {
chomp;
my @chunks = split;
my $key = shift @chunks;
push @keys, $key unless exists $data{$key};
foreach my $chunk (@chunks) {
$data{$key}{$chunk}++;
$all{$chunk} = 1;
}
}
my @fields = sort {$a <=> $b} keys %all;
my $l = max map {length} @fields;
foreach my $key (@keys) {
while (keys %{$data{$key}}) {
print $key, " ";
foreach my $field (@fields) {
if ($data{$key}{$field}) {
printf "%${l}s ", $field;
delete $data{$key}{$field} unless --$data{$key}{$field
+};
}
else {
printf "%${l}s ", "-";
}
}
print "\n";
}
}
__DATA__
0. 1 1 7 2 2 9 4 6 8 10 2
1. 10 1 6 3 4 9
2. 5 8 59 77 81 3
3. 16 17 19 23 3
The result:
0. 1 2 - 4 - 6 7 8 9 10 - - - - - - -
0. 1 2 - - - - - - - - - - - - - - -
0. - 2 - - - - - - - - - - - - - - -
1. 1 - 3 4 - 6 - - 9 10 - - - - - - -
2. - - 3 - 5 - - 8 - - - - - - 59 77 81
3. - - 3 - - - - - - - 16 17 19 23 - - -
Changing the sorting of fields if you have non-numeric fields is left as an exercise to the reader.