Re: array problems
by BrowserUk (Patriarch) on Aug 12, 2003 at 18:40 UTC
|
#! perl -slw
use strict;
use vars qw[ $a $b ];
use List::Util qw[ reduce ];
my $op = shift @ARGV;
my @hasharray;
for ( 2 .. @ARGV ) {
for my $indices ( Cnr( $_, 0..$#ARGV ) ) {
push @hasharray, {
LIST=> [ @$indices ],
VALUE=> reduce{
my $val = eval "$a $op $b";
} @ARGV[ @$indices ]
};
}
}
print "@{ $_->{LIST} } : $_->{VALUE}" for @hasharray;
exit;
sub Cnr{
my( $n, @r ) = shift;
return [] unless $n--;
for my $x ( 0 .. ($#_ - $n) ) {
push @r, map{ [ $_[$x], @$_ ] } Cnr( $n, @_[ ($x+1) .. $#_ ] )
+ ;
}
return @r;
}
Supply the (binary) operator as the first argument, the rest will be used as the values in the array.
A few runs P:\test>283241 + 1 2 3 4
0 1 : 3
0 2 : 4
0 3 : 5
1 2 : 5
1 3 : 6
2 3 : 7
0 1 2 : 6
0 1 3 : 7
0 2 3 : 8
1 2 3 : 9
0 1 2 3 : 10
P:\test>283241 - 1 2 3 4
0 1 : -1
0 2 : -2
0 3 : -3
1 2 : -1
1 3 : -2
2 3 : -1
0 1 2 : -4
0 1 3 : -5
0 2 3 : -6
1 2 3 : -5
0 1 2 3 : -8
P:\test>283241 * 1 2 3 4
0 1 : 2
0 2 : 3
0 3 : 4
1 2 : 6
1 3 : 8
2 3 : 12
0 1 2 : 6
0 1 3 : 8
0 2 3 : 12
1 2 3 : 24
0 1 2 3 : 24
P:\test>283241 / 1 2 3 4
0 1 : 0.5
0 2 : 0.333333333333333
0 3 : 0.25
1 2 : 0.666666666666667
1 3 : 0.5
2 3 : 0.75
0 1 2 : 0.166666666666667
0 1 3 : 0.125
0 2 3 : 0.0833333333333332
1 2 3 : 0.166666666666667
0 1 2 3 : 0.0416666666666667
Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
If I understand your problem, I can solve it! Of course, the same can be said for you.
| [reply] [d/l] [select] |
|
|
use List::Util;
use Algorithm::ChooseSubsets;
...<lots of stuff snipped here>...
# Generate sums of the values of all combinations of my picks
my @to_trade1;
for (my $i=0; $i < $roster_spots; $i++) {
my $record={};
my $this_pick = $pick_by_team[$brett_team][$i];
if ($this_pick > $draft_pick) {
push @to_trade1, $this_pick;
}
}
my @to_trade = {};
for (my $i = 2; $i < $#to_trade1; $i++) {
my $subset_list = new Algorithm::ChooseSubsets(\@to_trade1, $i);
while (my $this_set = $subset_list->next()) {
my $record={};
$record->{"LIST"} = [ @$this_set ];
$record->{"VALUE"} = List::Util::sum @$this_set;
push @to_trade, $record;
}
}
print Dumper(@to_trade);
This works, but is pretty slow...I have to respond to trades within a minute so, I may try some ways to speed it up! | [reply] [d/l] |
|
|
If your array size is always the same, then you can avoid having to regenerate the combinations each time.
In my version above, if you look closely you'll see that I don't permute the array elements. I permute the indices and the use those to slice the array. If your array is always the same size, you can do this once and reuse the indices each time which will save a fairly costly recursive generation each time.
A modified version of the above code to show this
If your array size varies, but over a short range, then you could use Memoize to cache the generation and only do it the first time a new array size is encountered.
As Algorithm::ChooseSubsets permutes the array rather than the indices, Memoizing that wouldn't reap the same rewards.
There is also a performance penalty from using OO-style interfaces, especially to inherently procedural algorithms. Most of the time this is pretty insignificant, but when it means issuing a call once each time around a loop instead of once at the top of the loop, then the overhead becomes a burden.
Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
If I understand your problem, I can solve it! Of course, the same can be said for you.
| [reply] [d/l] |
|
|
|
|
|
|
Does it really make sense to perform non-communtative operations on an unordered set?
| [reply] |
|
|
| [reply] |
|
|
This looks very good! I had just stumbled on List::Util myself and put it into an implementation that I thought would work. I'm testing mine now, assuming it works, I'll post it...otherwise, I'll use yours!!!!
Thanks!
| [reply] |
Re: array problems
by ctilmes (Vicar) on Aug 12, 2003 at 16:13 UTC
|
Might want to take a look at List::Permutor or Algorithm::Permute.
Update: Want combinations, not permutations.
Good luck on the homeworkFootball drafting tool!
| [reply] |
|
|
Yeah, I thought it would sound like a homework problem. I'm actually writing a drafting tool for my Fantasy Football league (16 rounds). I found a site that values each pick in the draft (www.footballguys.com) and I want to find all the combinations of my picks that are similar to the pick for which I want to trade.
I'll look at the permutations stuff, there might be something there.
| [reply] |
Re: array problems
by rupesh (Hermit) on Aug 12, 2003 at 16:43 UTC
|
My idea would be to pass the array to a funstion, manipualte the contents of each element and put it into a hash on the fly. That way, you could have one generic function, which would make your code much simpler, and much smaller too. However, if you want more info on array of hashes, hope this site proves useful All the best!
we're born with our eyes closed and our mouths wide open, and we spend our entire life trying to rectify that mistake of nature. - anonymous.
| [reply] |
Re: array problems
by eric256 (Parson) on Aug 12, 2003 at 17:13 UTC
|
You could push each index into a hash using the value as the key. Hope that makes some sense. I'll share my code if you share yours :-)
Update: I misunderstood. Thought you were going for list of matching values (don't know where i got that idea.) ___________
Eric Hodges
| [reply] |
|
|
Here is the beggining of a solution. It gives you all combinations of lenght x for a given set. So you could call it once for each length of your set and combine all those, to get all combinations of all lenghts.
Fun bit of recursion here. No promises it will always work.
use strict;
my @array = ["a","b","c","d"];
my $newlist = combine(2,@array);
foreach my $list (@$newlist)
{
print "[" . join(",", @$list) . "]\n";
}
# takes a list of items
# returns a list of lists of those items for each combination
sub combine {
my $length = shift;
my $items = shift;
my @list;
if ($length == 1)
{
foreach my $item (@$items)
{
push @list,[$item];
}
}
else
{
my $l = length(@$items) + 1;
foreach (0..$l) # once for each item
{
my $tempa = shift @$items; # get first item(a)
# get permutations for this set, but one
# shorter (without current item)
my $templist = combine($length-1,$items);
foreach my $i (@$templist)
{
unshift @$i,$tempa;
push @list,$i;
}
push @$items,$tempa;
}
}
return [@list];
}
1;
___________
Eric Hodges | [reply] [d/l] |
|
|
Before getting your response, I found Algorithm::ChooseSubset which takes the same tact. I'm working on that approach now...if I get it to work correctly, I'll post the solution. In essence, it does the same thing yours does!
| [reply] |
Re: array problems
by ido50 (Scribe) on Aug 12, 2003 at 16:37 UTC
|
Will be nice if you put the code you already have here.
-------------------------
Live fat, die young | [reply] |
|
|
Well, actually, I haven't coded the whole thing...it was just looking ugly as I started...I started out thinking I'd just check to see if I could find two of my picks that would be roughly the same value as the other guys pick, so here is the code I had:
foreach my $rec1 (@to_trade1) {
foreach my $rec2 (@to_trade1) {
if ($rec1->{"PICK"} != $rec2->{"PICK"}) {
my $trade_diff = $pot_trade_val - $rec1->{"VALUE"} - $rec2->{"
+VALUE"};
if (($trade_diff > 49) && ($trade_diff < 101)) {
$to_trade[$trade_cntr]->{"PICK_LIST"} = sort {$a <=> $b} ($r
+ec1->{"PICK"}, $rec2->{"PICK"});
$to_trade[$trade_cntr]->{"VALUE"} = $trade_diff;
}
That should give you the idea of where I was going with the following understanding:
| $pot_trade_val |
The value of the pick I want plus the 16th round pick held by the same team |
| $rec1 and $rec2 |
The same array copied twice and this is the list of picks I currently have. |
| $to_trade |
This is the set of picks that is within my tolerance to trade 50-100 points difference, of course, I'd walk this list and pull the one closest to 50 |
So, as I was going through this, I thought that it would end up pretty ugly and I'd only be able to account for say groups of three picks before the logic gets even worse. Thus, I thought it might be easier to value all my picks once, and then each time I was looking for a trade, I could just grep and sort the array of already calculated values! Sound like a good approach? | [reply] [d/l] |