# How to pick an element randomly using a probability vector?

Hi,

If I have an array such as arr=[0.6,0.1,0.3]
How can I write pick and index randomly using these numbers in javaScript?
like pick 0, 60% of the times.
1, 10% of the times
2, 30% of the times

Thanks

1 Like

I assume that sum of elements = 1.
The idea is to make a new array called `prArr` in which elements occurs as much times as their probability ratio.

``````let nums = [0.6, 0.1, 0.3]
let lc = 0.1

let randomPick = arr => {
let idx = 0, begin, count, prArr = []

arr.map(val => {
begin = idx
count = val / lc
for(; idx < count + begin; idx++)
prArr[idx] = val
})

let k = Math.floor(Math.random() * prArr.length)
return prArr[k]
}

for(let i = 0; i < 10; i++)
console.log(randomPick(nums))
``````

Live example

Tip: You can adjust `lc` to `0.01` or `0.001` based upon number of decimals

3 Likes

The idea is good. But you already have the probabilities so why not calculate with them?

You just do a Math.random(); and use this to get the index which correlates to this by using the cumulative probabilities, where every element has a certain area on the number scale from 0.0 up to 1.0 (e.g. element 0 is from 0.0 to 0.6, 1 is from 0.6 to 0.7 and 2 is 0.7 to 1.0):

``````const rnd = Math.random();
const arr = [0.6, 0.1, 0.3]

// The index and the cummulative probability
let index = -1;
let cum = 0;

// We add the cummulative probabilities and search till we get to where rnd is
arr.forEach((e, i) => {
if(rnd >= cum && rnd <  cum + e) {
index = i;
}
cum += e;
});
``````

Feel free to use also `findIndex()` method with the same idea behind it:

``````let cum = 0;
const rnd = Math.random();
const arr = [0.6, 0.1, 0.3];
const index = arr.findIndex(e => {  cum += e;  return rnd < cum && rnd >=  cum - e;})
``````

(I am sorry for naming the one variable â€ścumâ€ť)

4 Likes

@JaielSoft, another one, based on subtracting elements from random value in each loop

``````let nums = [0.6, 0.1, 0.3]

let randomPick = arr => {
let k = Math.random()
// get the first value that makes "rnd int" negative on subtraction
let res = arr.find(val => (k -= val) < 0)
return res || arr.pop() // else pop the last one
}

for(let i = 0; i < 10; i++)
console.log(randomPick(nums))
``````

For one-liners,

``````let randPick = (a, k=Math.random()) => a.find(v => (k -= v) < 0) || a.pop()
``````

Live example

1 Like

This one line works perfectly in the live example. But I am having trouble implementing it in my code.

what I did is create a function

`````` randPick = (a, k=Math.random()) =>{
a.find(v => (k -= v) < 0) || a.pop()
``````

}

Then in the main function that is running I used.

var randNum=this.randPick(percentVector[j]);
console.log(randNum);

For trying it I used

percentVector[j]=[0.5,0.5]

but the results is â€śundefinedâ€ť

sorry if this is a trivial question but I am new at using JavaScript

you used {} in the lambda function so you need to add a `return` statement. The original code didnt have them and a `return` is implied.

edit: So if you dont get it the solution:

``````randPick = (a, k=Math.random()) =>{
return a.find(v => (k -= v) < 0) || a.pop();
}
``````

(Although I dont like the `(k -= v)` statement because it doesnâ€™t adhere to general programming principals of making code that is easy to read and doesnâ€™t hold any surprises. Also altering the state of a parameter, that should always be treated as constant, is not the best practice. But if it works out itâ€™s fine. I like short code too after all)

1 Like

Thank you!
you are right the longer code is actually more readable and easier to understand. I preferred the one line because my code already contains multiple nested loops. I am trying to do things with no more loops for things to be faster.