my @A = (1,2,3,4,5,4,3,2,1,2);
my @B = (2,4,6,8,10,8,6,4,2);
my (%First, %Second);
push @{ $First{ $A[$_] } }, $_ for (0..$#A);
push @{ $Second{ $B[$_] } }, $_ for (0..$#B);
my %Pairs;
for my $Common (grep {exists $Second{$_}} keys %First){
for my $Idx (@{ $First{$Common} }){
push @{ $Pairs{$Common} }, map([$Idx, $_], @{ $Second{$Common} });
}
}
# Print out what we found
for (sort keys %Pairs){
print "$_:\n", map(" $_\n", map(join('-', @$_), @{ $Pairs{$_} })),
+"\n";
}
Now, the explanation:
After some sample data (@A and @B), we store each array's
values in a hash tying those values to their indices in the
array.
push @{ $First{ $A[$_] } }, $_ for (0..$#A);
push @{ $Second{ $B[$_] } }, $_ for (0..$#B);
%First refers to @A and %Second to @B. For example, '5' is
located at index 4 in @A, so its hash entry (if done
manually) would look like:
<nobr>$First{5} = [4]</nobr>
'8' would look like:
<nobr>$Second{8} = [3,5]</nobr> because it appears
at indices 3 and 5 in @B.
Now, we loop through all values common to both @A and @B:
for my $Common (grep {exists $Second{$_}} keys %First){
For each index in @A, we pair it up with each index in @B
and add the tuple to %Pairs
for my $Idx (@{ $First{$Common} }){
push @{ $Pairs{$Common} }, map([$Idx, $_], @{ $Second{$Common} });
}
When finished, %Pairs looks like this (pseudo-code, of course):
$Pairs{Each Common Value} = [ [A1, B1], [A1, B2], [A2, B1], [A2, B2]
+ ]
For example, '4' looks like:
$Pairs{4} = [[3,1], [3,7], [5,1], [5,7]]
Since I tried to do everything else in one line, I next
print out the contents of %Pairs. The output is:
2:
1-0
1-8
7-0
7-8
9-0
9-8
4:
3-1
3-7
5-1
5-7
None of this even resembles readable, easy-to-maintain code,
but it sure was fun to write! :-)
Russ
|