... print "Loaded. Generating combos...\n"; my @keys = sort keys %strings; # Now walk through the list. The best match for each string will be the # previous or next element in the list that is not from the original substring, # so for each entry, just look for the next one. See how many initial letters # match and track the best matches use MCE::Loop; MCE::Loop::init( max_workers => 8, chunk_size => 1, bounds_only => 1, ); my @ret = mce_loop_s { my ( $mce, $seq, $chunk_id ) = @_; my @best_overall_match = (0); # $seq->[0] and $seq->[1] have the same values when chunk_size => 1 for my $ki1 ( $seq->[0] .. $seq->[1] ) { for my $ki2 (($ki1 + 1)..$#keys) { my @strings = sort {$a->[0] cmp $b->[0]} @{$strings{$keys[$ki1]}}, @{$strings{$keys[$ki2]}}; my @matchdata = (0); # (length, index1-into-strings, index2-into-strings) for my $i1 (0..($#strings - 1)) { my $i2 = $i1 + 1; ++$i2 while $i2 <= $#strings and $strings[$i2][1] eq $strings[$i1][1]; next if $i2 > $#strings; my ($common) = map length, ($strings[$i1][0] ^ $strings[$i2][0]) =~ /^(\0*)/; next if $common < $minmatch; if ($common > $matchdata[0]) { @matchdata = ($common, [$i1, $i2]); } elsif ($common == $matchdata[0]) { push @matchdata, [$i1, $i2]; } } next if $matchdata[0] < $minmatch; if ($matchdata[0] > $best_overall_match[0]) { @best_overall_match = ($matchdata[0]); } if ($matchdata[0] >= $best_overall_match[0]) { push @best_overall_match, map { ["$strings[$_->[0]][1]:$strings[$_->[0]][2]", "$strings[$_->[1]][1]:$strings[$_->[1]][2]"] } @matchdata[1..$#matchdata]; } } # $ki2 } # $ki1 MCE->gather(\@best_overall_match); } 0, $#keys - 1; MCE::Loop::finish; my @best_overall_match = (0); for my $i ( 0 .. $#ret ) { if ($ret[$i]->[0] > $best_overall_match[0]) { @best_overall_match = @{ $ret[$i] }; } elsif ( $ret[$i]->[0] == $best_overall_match[0] ) { shift @{ $ret[$i] }; push @best_overall_match, @{ $ret[$i] }; } } print "Best overall match: $best_overall_match[0] chars\n"; ...