如何在Javascript中选择加权随机数组元素?

时间:2017-04-23 00:12:18

标签: javascript select random

例如:数组中有四个项目。我想随机得到一个,如下:

array items = [
    "bike"    //40% chance to select
    "car"     //30% chance to select
    "boat"    //15% chance to select
    "train"   //10% chance to select
    "plane"   //5%  chance to select
]

4 个答案:

答案 0 :(得分:3)

一些es6方法,使用通配符处理:

const randomizer = (values) => {
let i, pickedValue,
        randomNr = Math.random(),
        threshold = 0;

for (i = 0; i < values.length; i++) {
    if (values[i].probability === '*') {
        continue;
    }

    threshold += values[i].probability;
    if (threshold > randomNr) {
            pickedValue = values[i].value;
            break;
    }

    if (!pickedValue) {
        //nothing found based on probability value, so pick element marked with wildcard
        pickedValue = values.filter((value) => value.probability === '*');
    }
}

return pickedValue;

}

使用示例:

let testValues = [{
    value : 'aaa',
    probability: 0.1
},
{
    value : 'bbb',
    probability: 0.3
},
{
    value : 'ccc',
    probability: '*'
}]

randomizer(testValues); // will return "aaa" in 10% calls, 
//"bbb" in 30% calls, and "ccc" in 60% calls;

答案 1 :(得分:1)

当然可以。这是一个简单的代码:

    // Object or Array. Which every you prefer.
var item = {
    bike:40, // Weighted Probability
    care:30, // Weighted Probability
    boat:15, // Weighted Probability
    train:10, // Weighted Probability
    plane:5 // Weighted Probability
    // The number is not really percentage. You could put whatever number you want.
    // Any number less than 1 will never occur
};

function get(input) {
    var array = []; // Just Checking...
    for(var item in input) {
        if ( input.hasOwnProperty(item) ) { // Safety
            for( var i=0; i<input[item]; i++ ) {
                array.push(item);
            }
        }
    }
    // Probability Fun
    return array[Math.floor(Math.random() * array.length)];
}

console.log(get(item)); // See Console.

答案 2 :(得分:0)

以上两个答案都依赖于会很快变慢的方法,尤其是公认的方法。这种数组魔术将起作用:

var items = [
    "bike",    //40% chance to select
    "car",     //30% chance to select
    "boat",    //15% chance to select
    "train",   //10% chance to select
    "plane",   //5%  chance to select
];
var chances = [40, 30, 15, 10, 5]; //Chances of being selected

var sum = chances.reduce((acc, el) => acc + el, 0);
var acc = 0;
chances = chances.map(el => (acc = el + acc));
var rand = Math.random() * sum;
var result = items[chances.filter(el => el <= rand).length];

如果您将此设置为函数:

function chooseWeighted(items, chances) {
    var sum = chances.reduce((acc, el) => acc + el, 0);
    var acc = 0;
    chances = chances.map(el => (acc = el + acc));
    var rand = Math.random() * sum;
    return items[chances.filter(el => el <= rand).length];
}

此方法快速且易于阅读。它还具有易于更改的输入的优点:您可以轻松地将其更改为接受某种对象。

答案 3 :(得分:0)

我添加了我的解决方案作为一种适用于较小数组(无缓存)的方法:

    static weight_random(arr, weight_field){
    
        if(arr == null || arr === undefined){
            return null;
        }
        const totals = [];
        let total = 0;
        for(let i=0;i<arr.length;i++){
            total += arr[i][weight_field];
            totals.push(total);
        }
        const rnd = Math.floor(Math.random() * total);
        let selected = arr[0];
        for(let i=0;i<totals.length;i++){
            if(totals[i] > rnd){
                selected = arr[i];
                break;
            }
        }
    return selected;

}

像这样运行(提供数组和权重属性):

const wait_items =  [
    {"w" : 20, "min_ms" : "5000", "max_ms" : "10000"},
    {"w" : 20, "min_ms" : "10000", "max_ms" : "20000"},
    {"w" : 20, "min_ms" : "40000", "max_ms" : "80000"}
]   

const item = weight_random(wait_items, "w");
console.log(item);