sub array_intersect {
my ($arrays) = @_;
- return [] if @$arrays == 0;
- return $arrays->[0] if @$arrays == 1;
+ if (!ref($arrays->[0])) {
+ $arrays = [ grep { ref($_) eq 'ARRAY' } @_ ];
+ }
+
+ return [] if scalar(@$arrays) == 0;
+ return $arrays->[0] if scalar(@$arrays) == 1;
- my $return_arr;
- @$return_arr = array_unique(@{$arrays->[0]});
+ my $array_unique = sub {
+ my %seen = ();
+ return grep { ! $seen{ $_ }++ } @_;
+ };
+
+ # base idea is to get all unique members from the first array, then
+ # check the common elements with the next (uniquely made) one, only keep
+ # those. Repeat for every array and at the end we only have those left
+ # which exist in all arrays
+ my $return_arr = [ $array_unique->(@{$arrays->[0]}) ];
for my $i (1 .. $#$arrays) {
my %count = ();
- foreach my $element (@$return_arr, array_unique(@{$arrays->[$i]})) {
+ # $return_arr is already unique, explicit at before the loop, implicit below.
+ foreach my $element (@$return_arr, $array_unique->(@{$arrays->[$i]})) {
$count{$element}++;
}
$return_arr = [];
foreach my $element (keys %count) {
push @$return_arr, $element if $count{$element} > 1;
}
+ last if scalar(@$return_arr) == 0; # empty intersection, early exit
}
return $return_arr;
}
-sub array_unique {
- my %seen = ();
- return grep { ! $seen{ $_ }++ } @_;
-}
1;