简体   繁体   中英

How to randomly return associative array names based on its values

I've a set of campaigns that correspond to a number of "points." Looks something like this:

[ {"c1":4, "c2":8, "c3":25} ]

I want to randomly pick a campaign from this set. I'm assuming rand() will come into play at some point. However, I want the value of each to affect its chances of being picked.

So, for example, campaign "c2" should be picked twice as often as campaign "c1" (roughly). "c3" would be king, being most likely to be picked.

The number of campaigns and corresponding values may or may not be the same every time the script runs.

What's a good way to go about this?

That's easy. Just create another map that have CDF value for each campaign. For your example it will be:

0.108: C1
0.324: C2
1: C3

Then get a random number between 0 and 1. Go through the map and find the smallest number that is larger than the random number (you can binary search it or create a sorted hash map that can give smallest larger number also)

Note that by adding the probabilities the last entry may not add to 1 (can be 0.999). Just set it to 1 manually.

Here's a function that solves this for you. It creates a weighting array that you can use with a random number to properly weight each item per it's weighted value.

var campaigns = {"c1":4, "c2":8, "c3":24};

function getWeightedRandomCampaign(list) {
    var weighting = [];
    var total = 0;
    for (var item in list) {
        weighting.push({key: item, value: list[item]});
        total += list[item];
    }
    // generate random number between 1 and total
    var rand = Math.floor(Math.random() * total);
    // figure out which weighted slot it fits in
    var cum = 0;
    for (var i = 0; i < weighting.length; i++) {
        cum += weighting[i].value;
        if (rand < cum) {
            return(weighting[i].key);
        }            
    }
    return(weighting[weighting.length - 1]);
}

You can see it work here: http://jsfiddle.net/jfriend00/ffwqQ/


Here's how it works.

It starts with the campaigns objects and the weighting values.

var campaigns = {"c1":4, "c2":8, "c3":24};

Then, it builds a temporary data structure that looks like this:

var weighting = [{key: "c1", value: 4}, {key: "c2", value: 8}, {key: "c3", value: 24}];

While creating that data structure, it keeps track of the running total of all weight values.

It then creates a random number between 0 and that total.

It then walks through the weighting array adding up the values to find the first cumulative value that exceeds the random number. When it finds that, this is the slot that was selected.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM