all files / src/ WeightedRandomSelection.js

100% Statements 27/27
100% Branches 10/10
100% Functions 7/7
100% Lines 27/27
1 statement, 1 branch Ignored     
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68                12× 12×                               11× 11× 11×       111000×         111000× 129519× 129519× 129519×   129519×           111000× 111000×          
'use strict';
 
var _ = require('underscore'),
    Class = require('class.extend'),
    Stack = require('./Stack'),
    WeightedRandomSelection, reassignRanges;
 
reassignRanges = function() {
   var self = this,
       totalSoFar = 0.0;
 
   this._ranges = _(this._items).map(function(item) {
      totalSoFar += self._transformer(item);
      return totalSoFar;
   });
};
 
WeightedRandomSelection = Class.extend({
 
   init: function(transformer, items) {
      this._transformer = transformer;
      this.setItems(items || []).setAllowRepeatsDisregardDistance();
   },
 
   setItems: function(items) {
      this._items = items;
      reassignRanges.call(this);
      // reset our last item storage (stack) by resetting repeats allowed state
      this.setAllowRepeatDistance(this._allowRepeatDistance);
      return this;
   },
 
   setAllowRepeatsDisregardDistance: function() {
      return this.setAllowRepeatDistance(true);
   },
 
   setAllowRepeatDistance: function(distance) {
      this._allowRepeatDistance = distance;
      this._stack = (distance === true ? Stack.NO_OP : new Stack(distance));
      return this;
   },
 
   next: function() {
      var allowRepeats = (this._allowRepeatDistance === true) || (this._allowRepeatDistance >= this._items.length),
          iterationCount = 1,
          rand, ind;
 
      /* eslint-disable no-restricted-syntax, no-unmodified-loop-condition */
      do {
         rand = (Math.random() * this._ranges[this._ranges.length - 1]);
         ind = _.sortedIndex(this._ranges, rand);
         iterationCount += 1;
         // istanbul ignore if
         Iif (iterationCount > 10000) {
            throw new Error('Should not ever iterate more than 10,000 times trying to get next item.');
         }
      } while (!allowRepeats && this._stack.contains(ind));
 
      /* eslint-enable no-restricted-syntax, no-unmodified-loop-condition */
 
      this._stack.push(ind);
      return this._items[ind];
   },
 
});
 
module.exports = WeightedRandomSelection;