The code can be further (slightly) simplified:
-
[@res = sort @res] to [ sort @res ]
-
map {!$seen{"@$_"}++? $_:() }@results to grep { !$seen{"@$_"}++ } @results;
Be that as it may, johngg's approach of permuting indices is IMHO better because it is more general: it can be applied to an array of any mix of any type of elements with no worries about sorting:
c:\@Work\Perl\monks>perl
use strict;
use warnings;
use Test::More 'no_plan';
use Test::NoWarnings;
use Algorithm::Permute;
use List::MoreUtils qw(uniq);
use Data::Dump qw(dd);
my $ar_expected = [
qw(0+1+2 0+1+3 0+1+4 0+2+3 0+2+4 0+3+4 1+2+3 1+2+4 1+3+4 2+3+4)
];
my @arr = (1, 'two', -33, [ qw(f o u r) ], { V => 5 });
my $perm = Algorithm::Permute->new([ 0 .. $#arr ], 3);
my @allIndicePermsSorted;
while (my @res = $perm->next()) {
push @allIndicePermsSorted, [ sort { $a <=> $b } @res ];
}
my @uniqIndicePermsSorted =
map [ unpack 'N*', $_ ],
uniq
sort
map pack('N*', @$_),
@allIndicePermsSorted
;
my $ar_got = [ map join('+', @$_), @uniqIndicePermsSorted ];
is_deeply $ar_got, $ar_expected, 'unique sorted indices';
done_testing;
dd [ @arr[ @$_ ] ] for @uniqIndicePermsSorted;
exit;
__END__
ok 1 - unique sorted indices
1..1
[1, "two", -33]
[1, "two", ["f", "o", "u", "r"]]
[1, "two", { V => 5 }]
[1, -33, ["f", "o", "u", "r"]]
[1, -33, { V => 5 }]
[1, ["f", "o", "u", "r"], { V => 5 }]
["two", -33, ["f", "o", "u", "r"]]
["two", -33, { V => 5 }]
["two", ["f", "o", "u", "r"], { V => 5 }]
[-33, ["f", "o", "u", "r"], { V => 5 }]
ok 2 - no warnings
1..2
(Actually, I think there are permutation algorithms that give unique sets in their original order to begin with! (Update: See e.g. Algorithm::Combinatorics::combinations(); I'm sure there are others!))
Update: It might be advantageous to get rid of duplicates before sorting: gives sort less to do. For that, the somewhat syntactically awkward
my @uniqIndicePermsSorted =
map [ unpack 'N*', $_ ],
sort
+( uniq
map pack('N*', @$_),
@allIndicePermsSorted )
;
Give a man a fish: <%-{-{-{-<
|