Do your values need to maintain their order? If not, you could just use another layer of hashes. Instead of doing a push @{$hash{$key}}, $value;
, you would just do $hash{$key}{$value}++;
- and now keys %{$hash{$key}}
would show the unique values for that $key
. Order matching input would occur by random in small sets, sometimes. Usually won't happen.
If, however, you must maintain the order, you can use uniq
as indirectly suggested by AntonH. Another option, if you don't need the sorted list very often, i.e., if you add to the list more than you query, would be to use the hash, but add the current order value so you can sort them. For example:
# to "push"
$hash{$key}{$value} ||= scalar keys %{$hash{$key}} + 1;
# to get the list (Schwartzian Transform method)
my @values = map { $_->[1] } sort { $a->[0] <=> $b->[0] } map {
[ $hash{$key}{$_}, $_ ] } keys %{$hash{$key}};
And then, from here, you can create a data structure that does both at the same time - stores the list and the hash, only allowing adds to the list if the value isn't already in the hash. I'm assuming this is kind of what modules like Hash::Ordered do, even when not in pure perl.
# push
unless ($hash{hashes}{$key}) {
push @{$hash{arrays}{$key}}, $value;
$hash{hashes}{$key}{$value} = 1;
}
# get list
my @values = @{$hash{arrays}{$key}};
Just watch out - if you remove an item, you have to remove it from both the hashes and the arrays.