my @top_level; my %seen; my @cache; while (<>) { chomp; my ($key, @thingies) = split /\t/; unless ($seen{$key}) { push @top_level, $key; $seen{$key} = {}; } push @{$cache{$key}}, grep {!$seen{$key}{$_}++} @thingies; } foreach my $key (@top_level) { say join "\t", $key, @{$cache{$key}}; }