Home > Enterprise >  JS function that creates a range of numbers (inclusive beginning and end) with a limit on range item
JS function that creates a range of numbers (inclusive beginning and end) with a limit on range item

Time:05-20

You are given a starting number and ending number and the max number of output elements allowed. How would you create an output array with as even a distribution as possible, while still including the first and last points in the output?

Function signature

function generatePoints(startingNumber, endingNumber, maxPoints) {}

Function desired output

generatePoints(0, 8, 5) // [0, 2, 4, 6, 8]

Here's what I tried so far
function generatePoints(startingNumber, endingNumber, maxPoints) {
   const interval = Math.round((endingNumber - startingNumber) / maxPoints)
    let count = 0
    let counter = 0
    let points = []
   
    while(count < maxPoints - 1) {
        points.push(counter)
        counter =interval
        count  
    }

    points.push(endingNumber)

    return points
}

Technically this creates the correct output for the simple case, but falls short when up against most other edge cases due to the fact that I'm stopping one iteration early and then adding the final point. I'm thinking that the better way to do this (to create a better distribution) is to build from the center of the array outwards, versus building from the start of the array and then stopping one element early and appending the endingNumber.

CodePudding user response:

Do not Math.round(interval). Instead Math.round(counter) at that last moment.

The reason why is that if you've added k intervals, the error in what you're going can be as much as 0.5*k. But if you round at the last minute, the error is never more than 0.5.

CodePudding user response:

Note this:

  0       2       4       6        8
    -----   -----   -----   ----- 
      A       B       C       D

Splitting our range into intervals with 5 points including the endpoints, we have only four intervals. It will always be one fewer than the number of points. We can divide our range up evenly into these smaller ranges, simply by continually adding the width of one interval, which is just (endingNumber - startingNumber) / (maxPoints - 1). We can do it like this:

const generatePoints = (startingNumber, endingNumber, maxPoints) => Array .from (
  {length: maxPoints}, 
  (_, i) => startingNumber   i * (endingNumber - startingNumber) / (maxPoints - 1)
) 

console .log (generatePoints (0, 8, 5))

We just build an array of the right length, using the index parameter to count the number of smaller intervals we're using.

We do no error-checking here, and if maxPoints were just 1, we might have an issue. But that's easy enough to handle how you like.


But there is a concern here. Why is the parameter called maxPoints instead of points? If the number of points allowed is variable, I think we need further requirements.

  • Related