Lahari
Lahari

Reputation: 65

Split a range of min and max in N intervals

I have an array of min and max. I need a solution which is similar to this question but I have a min value as well. For example, I have an array [108090, 498090]. How do I add the min condition in the following function?

function getIntervalls(max, nbIntervalls) {
    var size = Math.round((max-1) / nbIntervalls);
    var result = [];

    for (let i = 0; i < nbIntervalls; i++) {
        var inf = i + i * size;
        var sup = inf + size < max ? inf + size: max;

        result.push([inf, sup]);
        if(inf >= max || sup >= max)break;
    }
    return result;
}
getIntervals(108090, 5)

The output of the above function is:

    [
     [
        0,
        99618
     ],
     [
        99619,
        199237
     ],
     [
        199238,
        298856
     ],
     [
        298857,
        398475
     ],
     [
        398476,
        498090
     ]
    ]

But I want to send the min value also. So my required should be like [108090, ...], [..,..], [..,..], [..,..], [..,498090].

Thanks in advance!!!

Upvotes: 2

Views: 1685

Answers (3)

Scott Sauyet
Scott Sauyet

Reputation: 50787

Note that this can also be done with a simple recursion. Something like this might be all you need:

const getIntervals = (min, max, count, end = min + (max - min) / count) =>
  count < 1 ? [] : [[min, end], ... getIntervals (end, max, count - 1)]

log (getIntervals (20, 62, 3))
log (getIntervals (108090, 498090, 5))
<script>const log = (o) => console .log (JSON.stringify(o))</script>

We recur on the number of subgroups still to create (count), calculating the end of the interval using the max, min, and count arguments.

But this does not increment the start of one group from the end of the previous one. We can do that with a minor adjustment:

const getIntervals = (min, max, count, end = min + (max - min + 1) / count - 1) =>
  count < 1
    ? []
    : [[min, end], ... getIntervals (end + 1, max, count - 1)]

log (getIntervals (21, 62, 3))
log (getIntervals (108091, 498090, 5))
<script>const log = (o) => console .log (JSON.stringify(o))</script>

This does the same thing as the above, but recurs using one more than the end of the previous group as the new minimum, rather than just using that end value as above.

Here we had to adjust the start value (or the end one) in order to get our counts correct and avoid non-integer endpoints. We switched from 108090 - 498090 to 108091 - 498090. This involves knowing how many values are in the range, and ensuring the count properly divides into that number.

If for instance, we tried getIntervals (21, 64, 6), we would get this:

[
  [21, 27.333333333333332],
  [28.333333333333332, 34.666666666666664],
  [35.666666666666664, 42],
  [43, 49.333333333333336],
  [50.333333333333336, 56.66666666666667],
  [57.66666666666667, 64]
]

We could do something a little different that will always work without the fractional endpoints, but will have groups that aren't exactly the same size:

const getIntervals = (min, max, count, end = min + Math.ceil ((max - min + 1) / count) - 1) =>
  count < 1 ? [] : [[min, end], ... getIntervals (end + 1, max, count - 1)]

log (getIntervals (21, 62, 3))
log (getIntervals (108090, 498090, 5))
log (getIntervals (21, 64, 6))
<script>const log = (o) => console .log (JSON.stringify(o))</script>

We introduce Math.ceil, and now getIntervals (21, 66, 6) returns the nicer:

[ 
  [21, 28],
  [29, 36],
  [37, 43],
  [44, 50],
  [51, 57],
  [58, 64]
]

here we have some number of results with n entries followed by others with n - 1 entries. Here we have two groups with eight entries each followed by four others with seven each. If we switched from Math .ceil to Math .floor, we would get the smaller groups first, and then the longer ones. But the important thing is that all the groups are within one element of the same size as the others.

Each of these possibilities uses a simple recursion for the job. It's pretty powerful!

Upvotes: 1

Afaq Ahmad
Afaq Ahmad

Reputation: 29

You can simply add min condition in interval size & inf calculation as

function getIntervalls(min, max, nbIntervalls) {
    var size = Math.round((max-min-1) / nbIntervalls);
    var result = [];
    var inf = min;
    var sup = 0

    for (let i = 0; i < nbIntervalls; i++) {
        inf = (i == 0)? inf : sup + 1;
        sup = (inf + size) < max ? inf + size: max;
        result.push([inf, sup]);
        if(sup >= max) break;
    }
    return result;
}

Upvotes: 1

AlexSp3
AlexSp3

Reputation: 2293

  • What I would do is to subtract the min value to the max value, so you are now working with numbers linearly related to the interval you passed as an argument.
  • Then, when you are pushing the result values just add again the min value:

function getIntervals(min, max, nbIntervalls) {
    max -= min;  // --------------------------> subtract min
    var size = Math.round((max-1) / nbIntervalls);
    var result = [];

    for (let i = 0; i < nbIntervalls; i++) {
        var inf = i + i * size;
        var sup = inf + size < max ? inf + size: max;

        result.push([inf + min, sup + min]);  // --------------------> add again min
        if(inf >= max || sup >= max)break;
    }
    return result;
}

console.log(getIntervals(108090, 498090, 5))

Upvotes: 2

Related Questions