http://qs321.pair.com?node_id=333937

gr0k has asked for the wisdom of the Perl Monks concerning the following question:

I'm working on an accounting problem where we have a list of checks and an amount. We need to find all possible combinations of checks that add together to make that amount. Basically if we had a record set like:
A - 10
B - 5
C - 13
D - 3
E - 15
F - 1
And we're searching for amount = 16. That would return 3 possible matches:
A + B + F
C + D
E + F
I came up with a way to do it using the Algorithm::Loops module and calculate all possible permutations down to a certain depth and ignore duplicates (such as ABF, AFB, BFA, etc are all the same thing). The problem is, we need to be able to search through potentially billions of combinations which takes a looooong time. I'm hoping to get some help optimizing my code to make it run faster. Right now with some tests I've run, this code can go through about 5 million combinations in about 3 minutes on a 2.4 ghz.
#!/usr/bin/perl use strict; use Algorithm::Loops qw(NestedLoops); my ($rs_ref,$key,$value,$sum,$count,%matches); my $amount = 16; my $depth = 6; $rs_ref->{'A'}->{'amount'} = 10; $rs_ref->{'B'}->{'amount'} = 5; $rs_ref->{'C'}->{'amount'} = 13; $rs_ref->{'D'}->{'amount'} = 3; $rs_ref->{'E'}->{'amount'} = 15; $rs_ref->{'F'}->{'amount'} = 1; my $start_time = time(); $count = NestedLoops( [ ( [keys %{$rs_ref}] ) x $depth ], { OnlyWhen => sub { @_ == keys %{{@_,reverse@_}}; } }, sub { $sum = 0; foreach $key(@_) { $value = $rs_ref->{$key}->{'amount'}; $sum += $value; } if ($sum == $amount) { $matches{join ' ', sort { $a cmp $b} @_} = 1; } }, ); print "Searched $count combinations...\n"; foreach $key (keys %matches) { print "MATCH: $key\n"; } my $end_time = time(); print "Finished in " . ($end_time - $start_time)/60 . " minutes.\n";
Which prints out:
Searched 1956 combinations...
MATCH: E F
MATCH: A B F
MATCH: C D
Finished in 0.0166666666666667 minutes.