OK - more robust version:
use strict;
use warnings;
use Digest::MD5;
use Data::Dumper;
my @test_data = (
{ Tag1 => "1", Tag2 => "a" },
{ Tag1 => "1", Tag2 => "a" },
{ Tag1 => "1", Tag2 => "b" },
{ Tag1 => "1", Tag2 => "c" },
{ Tag1 => "1", Tag2 => "a" },
{ Tag1 => "2", Tag2 => "a" },
{ Tag1 => "2", Tag2 => "d" },
{ Tag1 => "2", Tag2 => "a" },
{ Tag1 => "3"},
{ Tag1 => "sun", Tag2 => "a" },
{ Tag1 => "sun", Tag2 => "a" },
);
my @test2=(
{ a=>1, b=>2 },
{ ab => 12}
);
# for performance, MD5 is fastest.
my %unique = map {my @k=sort(keys %$_);
my $ctx=Digest::MD5->new() or die "Cannot make MD5 o
+bj";
$ctx->add($_ . $;) for @k;
$ctx->add("=>"); #separator for values
$ctx->add($_ . "+") for @$_{@k};
$ctx->digest() => $_ }
@test_data;
print Dumper [values %unique];
%unique = map {my @k=sort(keys %$_);
my $ctx=Digest::MD5->new() or die "Cannot make MD5 ob
+j";
$ctx->add($_ . $;) for @k;
$ctx->add("=>"); #separator for values
$ctx->add($_ . "+") for @$_{@k};
$ctx->digest() => $_ }
@test2;
print Dumper [values %unique];
"From there to here, from here to there, funny things are everywhere." -- Dr. Seuss