How to use a single value to map to multiple percentages?

196 Views Asked by At

I am a programmer so please bear with me!

I am given a percent, represented by a value of 0-1. I want to map evenly spaced percents where I know the total amount of areas and the index of the area I'd like to reference.

For example, given 0.5 and having 4 areas to relate to it would look like the following:

0.5:
[0] = 1 // because 0-0.25 is full
[1] = 1 // because .25-.5 is full
[2] = 0 // because .5-.75 is empty
[3] = 0 // because .75-1 is empty

Or in the case that the number does not map evenly:

0.66:
[0] = 1 // because 0-.25 is full
[1] = 1 // because .25-.5 is full
[2] = .64 // because .5-.75 is a fractional area (.66 - .5 = .16 / .25 = .64)
[3] = 0 // because .75-1 is empty

Currently I have the following solution in js

/**
 * Get a section of a percent similar to an array (with array indices) related back to
 * a total amount of sections.
 * @param {number} percent Between 0 and 1
 * @param {number} section Section to query on, array indexed
 * @param {number} sections Of sections that the Percent is split into
 */
const getSectionOfPercent = (percent, section, sections = 3) => {
    // if our current section isn't a fraction, return 1 or 0
    if(percent * sections > section + 1) {
        return 1;
    } else if(percent * sections < section) {
        return 0;
    }

    // return the fraction of the percent for our section
    return percent - (section / sections);
};

My question: Is it possible to do this purely as a mathematical transform without having to do conditionals? What does that equation look like? I haven't been able to figure anything out.

Thanks!

2

There are 2 best solutions below

2
On

I think you'll get what you need just by multiplying the percent by the number of bins.

For example, $4 \times 0.66 = 2.64$. Use a floor function to get the integer part ($2$ - call this integer fullBins), and then subtract that from the full number to get the decimal part ($0.64$ - call this decimal leftOver).

Initialize everything in your array to 0. Now, assign a value of 1 to the first fullBins elements in your array, and assign leftOver to the next element (the fullBinsth element if your array is zero-based).

0
On

EDIT: Found that using a heaviside vs what I had previous made it a lot simpler so updating with that

Still working on finding an answer I prefer. Found an alternative way to do this that is closer to what I'd like to do. It is basically what I did previously but more of a pure transform.

Basically any section can be simplified to be either 0%, 100%, or the left over percent area. That can be determined by subtracting the current section stop as a fraction from the percentage. That isolates the percent, and we can rely on that being clamped to 0 - 1 if out of bounds.

That looks like this in code

/**
 * Get a section of a percent similar to an array (with array indices) related back to
 * a total amount of sections.
 * @param {number} percent Between 0 and 1
 * @param {number} section Section to query on, array indexed
 */
const getSectionOfPercent = (percent, section) => clamp(
    ((percent) - (section / 4)) /
    (1 / 4),

    // clamp back to 0 & 1
    0,
    1,
);