This is my approach using simple JS. I added a few more numbers to your example to better test it.
I use a new array to store the number of occurrences in each interval. The first position will represent the number of elements <interval, the second <2 * interval ... etc. Etc.
I keep a reference to the last valid index so that I can fill in empty cells with zeros.
UPDATE: Minor fix to exclude the first number as undefined when there is no value in the range 0 <= x <= 3
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
UPDATE 2:. Version using underscore. It uses countBy to get intervals and avoids using Array.prototype.fill because it is an ES6 function.
function getZeroFilledArr(len) { return Array.apply(null, Array(len)).map(Number.prototype.valueOf, 0); } function getIntervalLentgh(intervals) { return Number(_.max(intervals)) + 1; } var arr = [110, 113, 116, 119], interval = 3, intervals = _.countBy(arr, function(el) { var intPart = Math.floor(el / interval); return el && intPart * interval === el ? intPart - 1 : intPart; }), zeroFilledArr = getZeroFilledArr(getIntervalLentgh(_.keys(intervals))); console.log(_.reduce(intervals, function(memo, value, key) { memo[key] = value; return memo; }, zeroFilledArr));
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
source share