I think that the main task is to randomly select "events" (objects) from the os array with a frequency determined by their respective weight s. The approach is to map (i.e., search) a random number (with a uniform distribution) onto the cumulative distribution function of the start function.
With positive weights, their total amount increases from 0 to 1. The code that you gave us is just looking from the end 0. To maximize speed on repeated calls, pre-calculate the amounts and organize events so that at first there are the largest weights.
It doesnβt really matter if you perform an iteration (loop) or recursion search. Recursion is good in a language that tries to be "purely functional" but does not help to understand the underlying mathematical problem. And this will not help you pack the task into a pure function. underscore functions are another way to package iterations, but don't change the main functions. Only any and all exit earlier when the target is found.
For a small os array, this simple search is enough. But with a large array, binary search will be faster. Looking in the underscore , I find that sortedIndex uses this strategy. From Lo-Dash (a underscore dropin): "Uses a binary search to determine the smallest index at which the value should be inserted into the array to maintain the sort order of the sorted array"
The main use of sortedIndex :
os = [{name:'one',weight:.7}, {name:'two',weight:.25}, {name:'three',weight:.05}] t=0; cumweights = (t+=o.weight for o in os) i = _.sortedIndex(cumweights, R) os[i]
You can hide the calculation of the total amount using a nested function, for example:
osEventGen = (os)-> t=0; xw = (t+=y.weight for y in os) return (R) -> i = __.sortedIndex(xw, R) return os[i] osEvent = osEventGen(os) osEvent(.3)
In coffeescript, a Jed Clinger recursive search can be written as follows:
foo = (x, r, t=0)-> [y, x...] = x t += y return [y, t] if x.length==0 or t>r return foo(x, r, t)
The loop version using the same basic idea:
foo=(x,r)-> t=0 while x.length and t<=r [y,x...]=x
Tests for jsPerf http://jsperf.com/sortedindex assume that sortedIndex faster when os.length is around 1000, but slower than a simple loop when the length is greater than 30.