note
AnomalousMonk
<p>
I share the concerns of others about mixing too much Perl majick together: the result may blow up in your (or your maintainer's) face in very unexpected ways. But as to some tangential questions...
<blockquote><i>
Is there an efficient way to check whether the values of a hash are unique?
</I></BLOCKQUOTE>
<c>
c:\@Work\Perl\monks>perl -wMstrict -le
"my %h = qw(a 1 b 2 c 3 d 1);
;;
my %r = reverse %h;
keys %r == keys %h or die qq{hash @{[ %h ]} not unique};
"
hash c 3 a 1 b 2 d 1 not unique at -e line 1.
</C>
<blockquote><i>
... a solution to return several values if the hash is not unique ...
</I></BLOCKQUOTE>
The general approach to maintaining several values for a hash key is an anonymous array. Maybe something like:
<c>
c:\@Work\Perl\monks>perl -wMstrict -le
"use Data::Dump qw(dd);
;;
my %h = (
a => [ 1 ], b => [ 2, 99, 88 ], c => [ 3 ], d => [ 1, 99 ]
);
;;
my %r;
for my $hk (keys %h) {
push @{ $r{$_} }, $hk for @{ $h{$hk} };
}
dd \%r;
"
{ 1 => ["a", "d"], 2 => ["b"], 3 => ["c"], 88 => ["b"], 99 => ["b", "d"] }
</C>
<b>Update:</B> Note that this inversion approach for multi-value hashes is not round-tripable unless you consider the arrays of values to be <i>unordered</I> lists:
<c>
c:\@Work\Perl\monks>perl -wMstrict -le
"use Test::More 'no_plan';
use Test::NoWarnings;
;;
use Data::Dump qw(dd);
;;
my %h = (
a => [ 1 ], b => [ 2, 99, 88 ], c => [ 3 ], d => [ 1, 99 ]
);
;;
my %r = invert(%h);
dd \%r;
;;
my %rr = invert(%r);
dd \%rr;
;;
is_deeply \%rr, \%h, 'round trip';
;;
done_testing;
;;
exit;
;;
sub invert {
my %h = @_;
my %r;
for my $hk (keys %h) {
push @{ $r{$_} }, $hk for @{ $h{$hk} };
}
return %r;
}
"
{ 1 => ["a", "d"], 2 => ["b"], 3 => ["c"], 88 => ["b"], 99 => ["b", "d"] }
{ a => [1], b => [99, 88, 2], c => [3], d => [99, 1] }
not ok 1 - round trip
# Failed test 'round trip'
# at -e line 1.
# Structures begin differing at:
# $got->{b}[0] = '99'
# $expected->{b}[0] = '2'
1..1
ok 2 - no warnings
1..2
# Looks like you failed 1 test of 2.
</C>
</P>
<!-- Node text goes above. Div tags should contain sig only -->
<div class="pmsig"><div class="pmsig-634253">
<hr><p>Give a man a fish<b>:</B> <c> <%-{-{-{-<</C></P>
</div></div>
11111535
11111535