inherit
40157
tyrantlytamale 627939549 tjhtmlmaniac
0
Sept 3, 2023 15:17:02 GMT -8
Tylr
The stale taste of recycled air.
2,964
April 2005
tyrantlytamale
|
Post by Tylr on Apr 3, 2012 21:47:19 GMT -8
I have a strange programming hangup. I'm working in PHP, and I am creating a segment of code that chooses randomly between a set of items. The number of items it is choosing between varies, typically 1-5. Each of those items has a percentage attached to it, and I want that percentage to be the percentage chance that it will be the item selected.
The best way I've thought of to do this is to create an array of 100 items, each referencing one of the items I'm choosing between, and randomly pick one.
Is there a simpler method I'm not seeing?
|
|
inherit
24252
0
Aug 1, 2023 15:01:24 GMT -8
coolcoolcool
When the world says, "Give up," Hope whispers, "Try it one more time."
2,148
May 2004
coolcoolcool
|
Post by coolcoolcool on Apr 6, 2012 19:02:28 GMT -8
This can easily be done a lot more elegantly than using an array of 100 items.
Considering it's a small set of items, you might as well just brute force it. There are a variety of ways of doing it .. all depending on the details of your code, but one possibility would be generating a random number from 0 to 1. Then loop through your items and subtract their probabilities from the generated number.
Whenever the randomly generated number reaches zero, then that is the selected item. This is all assuming your items are ordered randomly on each iteration.
That's about the best I can think of without seeing your source code.
|
|
inherit
40157
tyrantlytamale 627939549 tjhtmlmaniac
0
Sept 3, 2023 15:17:02 GMT -8
Tylr
The stale taste of recycled air.
2,964
April 2005
tyrantlytamale
|
Post by Tylr on Apr 6, 2012 19:17:27 GMT -8
$possible_campaign[0]['percentage']=30; $possible_campaign[0]['id']=1; $possible_campaign[1]['percentage']=20; $possible_campaign[1]['id']=6; $possible_campaign[2]['percentage']=50; $possible_campaign[2]['id']=8;
$i=1; $current_percent=0; foreach($possible_campaign as $this_possible_campaign){ $current_percent=$current_percent+$this_possible_campaign['percentage']; while($i<$current_percent){ $isit[$i]=$this_possible_campaign['id']; $i++; } } $picked_c_id=$isit[rand(1,100)];
The $possible_campaigns are just an example of what I might have at that point in the code. They won't be in random order unless I resorted the array.
|
|
#00AF33
Bark Different.
102833
0
1
Feb 12, 2023 16:57:46 GMT -8
RedBassett
I'm a Marxist/Lennonist of the Groucho/John variety.
15,405
April 2007
applecomputer
RedBassett's Mini-Profile
|
Post by RedBassett on Apr 6, 2012 20:48:43 GMT -8
Not sure if this is what you wanted, but here is what i came up with: function selectCampaign($campaigns) { $i = rand(0, 100); $stack = 0; foreach ($campaigns as $camp) { if ($i > $stack && $i > ($camp['per'] + $stack)) $stack += $camp['per']; else { $select = $camp['id']; break; } } return $select; } The parameter is an array, in this format: $campaigns = array( array('per' => 50, 'id' => 0), array('per' => 30, 'id' => 1), array('per' => 20, 'id' => 2) ); I tried writing it with a checker that would make sure the percents added to 100%, and scale if not, but it is too late to do that math right now - RedBassett
|
|
inherit
130228
0
Jul 11, 2024 19:19:59 GMT -8
Charles Stover
1,731
August 2008
gamechief
|
Post by Charles Stover on Apr 7, 2012 15:08:36 GMT -8
This probably isn't exact odds, so maybe run it through a simulator with a ton of iterations to make sure.
$whatever = Array( Array( 'chance' => 50, 'id' => 1 ), Array( 'chance' => 30, 'id' => 3 ), Array( 'chance' => 20, 'id' => 7 ) );
$winner = null; while ($winner == null) { $chance = rand(0, 100); $item = rand(0, count($whatever) - 1); if ($whatever[$item]['chance'] < $chance) $winner = $whatever[$item]['id']; }
|
|
inherit
97216
0
Nov 23, 2024 12:51:52 GMT -8
Bennett 🚀
Formerly iPokemon.
3,622
January 2007
catattack
iPokemon's Mini-Profile
|
Post by Bennett 🚀 on Apr 13, 2012 19:51:50 GMT -8
Doing a weighted array could perhaps help you with this.
<?php $items = array( array( "item"=>"Something", "weight"=>10 ), array( "item"=>"Something Else", "weight"=>90 ) ); $weighted = array(); foreach($items as $val){ for($x=0;$x<$val["weight"];$x++){ $weighted[] = $val["item"]; } } $r = array_rand($weighted,3); echo $weighted[$r[rand(1,3)]]; ?>
|
|
inherit
130228
0
Jul 11, 2024 19:19:59 GMT -8
Charles Stover
1,731
August 2008
gamechief
|
Post by Charles Stover on Apr 14, 2012 15:29:13 GMT -8
That is ridiculously memory intensive, though. There is surely a way to do it without resorting to that, which is what I tried to do. I'm sure some combination of rand() and comparison statements can weight a value.
|
|
inherit
40157
tyrantlytamale 627939549 tjhtmlmaniac
0
Sept 3, 2023 15:17:02 GMT -8
Tylr
The stale taste of recycled air.
2,964
April 2005
tyrantlytamale
|
Post by Tylr on Apr 14, 2012 18:47:53 GMT -8
Stackoverflow had a thread about this. Here's what I got: $sum = 0; $choice = rand(1,100); foreach ($possible_campaign as $item) { $sum += chance($item); if ($sum >= $choice) { $picked=$item['id']; } }
|
|
#00AF33
Bark Different.
102833
0
1
Feb 12, 2023 16:57:46 GMT -8
RedBassett
I'm a Marxist/Lennonist of the Groucho/John variety.
15,405
April 2007
applecomputer
RedBassett's Mini-Profile
|
Post by RedBassett on Apr 14, 2012 20:40:53 GMT -8
Stackoverflow had a thread about this. Here's what I got: $sum = 0; $choice = rand(1,100); foreach ($possible_campaign as $item) { $sum += chance($item); if ($sum >= $choice) { $picked=$item['id']; } } I realize I could have reduced all the ifs in mine to look a lot like that!
|
|
inherit
40157
tyrantlytamale 627939549 tjhtmlmaniac
0
Sept 3, 2023 15:17:02 GMT -8
Tylr
The stale taste of recycled air.
2,964
April 2005
tyrantlytamale
|
Post by Tylr on Apr 14, 2012 21:01:10 GMT -8
Yeah, the concept between yours, Stover's, and that last one is definitely the same.
As far as exact odds, the odds will be exactly the same as they were for the array in the OP. The loop just doesn't have to run as many iterations.
|
|
#00AF33
Bark Different.
102833
0
1
Feb 12, 2023 16:57:46 GMT -8
RedBassett
I'm a Marxist/Lennonist of the Groucho/John variety.
15,405
April 2007
applecomputer
RedBassett's Mini-Profile
|
Post by RedBassett on Apr 15, 2012 16:40:06 GMT -8
I added a bunch of lines to break the loop if the right number had been reached. I guess my checking and loop breaking is an advantage, only after you scale system to a large number of entries.
|
|
inherit
40157
tyrantlytamale 627939549 tjhtmlmaniac
0
Sept 3, 2023 15:17:02 GMT -8
Tylr
The stale taste of recycled air.
2,964
April 2005
tyrantlytamale
|
Post by Tylr on Apr 15, 2012 17:09:46 GMT -8
I guess my checking and loop breaking is an advantage, only after you scale system to a large number of entries. This is true, but I'm not anticipating more than two or three entries at one time when this is called. ;-)
|
|
#00AF33
Bark Different.
102833
0
1
Feb 12, 2023 16:57:46 GMT -8
RedBassett
I'm a Marxist/Lennonist of the Groucho/John variety.
15,405
April 2007
applecomputer
RedBassett's Mini-Profile
|
Post by RedBassett on Apr 15, 2012 17:10:44 GMT -8
I guess my checking and loop breaking is an advantage, only after you scale system to a large number of entries. This is true, but I'm not anticipating more than two or three entries at one time when this is called. ;-) You don't want items with a .00463% chance of appearing?
|
|
inherit
40157
tyrantlytamale 627939549 tjhtmlmaniac
0
Sept 3, 2023 15:17:02 GMT -8
Tylr
The stale taste of recycled air.
2,964
April 2005
tyrantlytamale
|
Post by Tylr on Apr 15, 2012 17:30:56 GMT -8
Haha. If I wanted to be that specific, I'd probably keep track of every time it appeared and just bring it up when it was below the threshold.
|
|
#00AF33
Bark Different.
102833
0
1
Feb 12, 2023 16:57:46 GMT -8
RedBassett
I'm a Marxist/Lennonist of the Groucho/John variety.
15,405
April 2007
applecomputer
RedBassett's Mini-Profile
|
Post by RedBassett on Apr 15, 2012 17:34:31 GMT -8
;D
|
|