To do this, I need to reconcile the discrepancies between the lists and come up with an array of arrays holding the indexes.
Have a look at
List::Compare. Following code does build a hash of arrays holding the indexes (you may need to replace the ' ' string (being used for undef values) with undef; I used it in favor of undef, because undef would garble the output). Basically, it should work for an infinite amount of sets.
#!/usr/bin/perl
use strict;
use warnings;
use List::Compare;
my (%have,
@seen,
%is_unique);
my @sets = (
[qw( a c f g e h i )], # X
[qw( a b c d e f g h i )], # Y
[qw( a c d e f g h i )], # Z
);
my $lcm = List::Compare->new(@sets);
foreach my $set (@sets) {
my %seen = map { $_ => 1 } @$set;
push @seen, \%seen;
}
foreach ($lcm->get_intersection) {
$have{$_} = [ 0..$#sets ];
}
my %index = map { $_ => undef } 0..$#sets;
foreach my $i (0..$#sets) {
foreach my $elem ($lcm->get_unique($i)) {
my @list;
foreach (keys %index) { $list[$_] = $index{$_} }
$list[$i] = $i;
$have{$elem} = [ @list ];
$is_unique{$elem}++;
}
}
foreach my $elem ($lcm->get_nonintersection) {
next if $is_unique{$elem};
my @list;
foreach (keys %index) { $list[$_] = $index{$_} }
foreach my $i (0..$#sets) { $list[$i] = $i if $seen[$i]{$elem} }
$have{$elem} = [ @list ];
}
foreach (sort keys %have) {
foreach my $i (0..@{$have{$_}}) {
print defined $have{$_}->[$i] ? "$_ " : ' ';
}
print "\n";
}
__OUTPUT__
a a a
b
c c c
d d
e e e
f f f
g g g
h h h
i i i