Distribute or scale a specific value to an array of numbers

I'm currently working on a project that involves distributing the values of an array in a way that the total sum equals 100.

Here are some examples:

  • [70, 34, 92] with a total value of 100. The output is [35.71, 17.35, 46.94] because 35.71 + 17.35 + 46.94 = 100.
  • [86, 99.5, 100] with a total value of 100. The output is [30.12, 34.85, 35.03].
  • [96, 37] with a total value of 100. The output is [72.18, 27.82].
  • [98, 76.5, 68.5, 63.5, 38.5] with a total value of 100. The output is
    [28.41, 22.17, 19.86, 18.41, 11.15]
    which equals 100 when summed up.

My current approach is as follows:

  • Add all the values in the given array
  • Multiply each value by 100
  • Divide each value by the total sum
  • Use .toFixed(2).

The calculation formula used:

+(((valueOfArray * 100) / totalSumOfGivenArray).toFixed(2))

However, my initial solution sometimes falls short of returning exactly 100 due to decimal issues like 99.99, 99.999999, 100(mostly), 100.0000000001, 99.999978, 100.09999999, 99.000009. This has led me to consider other approaches.

Another method I explored goes as follows:

let i = 0;
for(i = 0;  i < controlsKey.length-1; i++){
  let formId = controlsKey[i];
  relValue = this.getDistributedValue(+form.controls[formId].value, totalActualSum); // returns formula result
  form.controls[formId].setValue(relValue))
  relativeSum = relativeSum + relValue;
}
relValue = 100 - relativeSum;
form.controls[controlsKey[i]].setValue(relValue)

This method works well too, but I am still seeking a more elegant solution for this problem.

The initial solution is acceptable to me, even though there are some lingering decimal issues despite using .toFixed(2).

Answer №1

To avoid dealing with floating point values, you can utilize integer numbers and subtract them from a base value of 10000 (equal to 100 with two decimal places). This method involves creating an array of strings where each number has a dot inserted at the appropriate place to achieve the desired formatted string.

const formatNumber = num => num.toString().replace(/\d\d$/, '.$&');

function convertToPercentage(array) {
    var totalSum = array.reduce((a, b) => a + b),
        offset = 1e4;
    return array.map((value, index, { length }) => {
        if (index + 1 === length) return formatNumber(offset);
        var percentage = Math.round(value * 1e4 / totalSum);
        offset -= percentage;
        return formatNumber(percentage);
    });
}

console.log(...convertToPercentage([70, 34, 92])); // [35.71, 17.35, 46.94] 
console.log(...convertToPercentage([86, 99.5, 100]); // [30.12, 34.85, 35.03]
console.log(...convertToPercentage([96, 37]); // [72.18, 27.82]
console.log(...convertToPercentage([98, 76.5, 68.5, 63.5, 38.5]); // [28.41, 22.17, 19.86, 18.41, 11.15]

Answer №2

One major challenge lies in the inherent inaccuracy of floating point numbers. Without utilizing toFixed, it becomes nearly impossible to rectify this issue. Even if one identifies the error, selects an element, and adjusts it by the error amount, the final result will still be off in a different direction due to the limited precision capabilities of floating point numbers during operations:

function calculateDistribution(data) {
    var total =  data.reduce((acc, val) => acc + val, 0)
    var distribution = data.map(d => 100 * d / total)
    var error = distribution.reduce((acc, val) => acc + val, 0) - 100;
    console.log({distribution, error});
    distribution[0] -= error;
    error = distribution.reduce((acc, val) => acc + val, 0) - 100;
    console.log({distribution, error});
}

calculateDistribution([98, 76.5, 68.5, 63.5, 38.5]);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Activate a button only when a value is inputted into a text box associated with a chosen radio button

I'm facing a challenge with my radio buttons and sub-options. When a user selects an option, the corresponding sub-options should be displayed. Additionally, I want to enable the next button only when text is entered in all sub-option text boxes for t ...

Javascript echoes are appearing in an alert rather than being processed

My registration system utilizes AJAX to process form data and return a false value. The JavaScript code snippet shown at the top handles this functionality. Upon submitting the form, the data is sent to join.php where it undergoes validation to ensure no d ...

Engage in a conversation with a specific individual on the internet using node.js

Looking to implement a chat feature with specific online users similar to Facebook or Gmail using node.js and socket.io. Can anyone assist me with this? Thanks in advance! Client.html <html> <head> <title>My Chat App</title> <d ...

Is there a way to eliminate elements from the second array and add them to the first array in PostgreSQL when working with two arrays?

If I have a table called t with two columns A1 and A2, the structure would be like this: A1 A2 ID 1,3,6,9,11 3,9 1 2,3,5,7 3 2 ... I am looking to add another column with the following results: A3 1,6,11 2,5,7 ... The values are sto ...

The integration of reduce and scan with a specific focus

RxJS version: 5.5.2 Working with an array const v = [1, 2, 3]; The goal is to convert this array into a Subject initially acting like an Observable until all values (1, 2, 3) are consumed. After that, it should behave like a Subject. The challenge lies ...

Tips for passing arguments to event handlers in React JS

While going through the React JS documentation, I came across the concept of "Lifting State Up" and I have some confusion about it. You can check out the codepen sample here: https://codepen.io/valscion/pen/jBNjja?editors=0010 In the TemperatureInput comp ...

trigger form submission and refresh on React JSON Schema Form

I'm currently utilizing react-jsonschema-form to create a form, but I'm facing an issue where the function linked to the onSubmit button isn't executing. It's puzzling why clicking the button causes the page to reload without running th ...

"Troubleshooting a datatype problem on my localhost XAMPP server

A TypeError was encountered: The function trim() requires a string as Argument #1, but an array was provided in C:\xampp\htdocs\php\required_valid_form.php:52. Are there any syntax errors causing conflicts? <?php $name=$email=$we ...

Obtain the count of a two-value array from a Laravel controller and pass it to JavaScript

I need help with a query that calculates the count based on conditions for genders "male" and "female". $users[] = User::whereIn('gender',array('male', 'female'))->count()->get(); return view('/',comp ...

What is the process for converting a two-column matrix into a structure resembling a multimap?

Is there a way to convert a matrix with 2 columns into a multimap or list of lists? The matrix's first column contains IDs (which may be duplicated) and the second column contains values. For instance, consider the following matrix: m <- matrix( ...

Ways to incorporate scroll buttons on both sides for dynamically generated tabs

When the number of generated tabs exceeds a certain limit, they start appearing on the next line and it looks odd. I want to implement a right and left scroll option for better navigation. However, being new to scripting, I am unsure about how to include t ...

Tips for transferring information using '&' on websites

When using jQuery's $.ajax method to send data to add_showcase.php, an issue arises when passing a complex data structure as the "desc" parameter. The data might not be received in its entirety by the PHP file. $.ajax({ type: "GET", ...

Updating state of an array nested inside an object using React and ES6

I'm fairly new to Javascript and I feel like my lack of fundamental knowledge might be hindering me from solving this issue. Despite trying different approaches and reading tutorials, I can't seem to get it right. My goal is to manipulate the st ...

Transferring an array from PHP to jQuery through the use of AJAX

My JavaScript code communicates with a PHP page to retrieve data from a database and store it in an array. Now, I would like to use jQuery to loop through that array. This is how the array is structured: Array ( [0] => Array ( [image] => articl ...

Designing geometric forms using the vertices of a Sphere in ThreeJs

My current project involves creating shapes based on vertices that have already been generated using a formula. I have successfully connected lines between these vertices using a threejs method, but now I want to take it a step further and create map tiles ...

Having Trouble Retrieving Image File Contents in Laravel Production Environment

My code below is functioning properly on localhost during development. <img class="img-fluid rounded-circle" src="{{ url('image?type=user&file='.Auth::user()->picture_file.'&mime='.Auth::user()->picture_mime) }}" alt=" ...

Uncovering the Issue with Select All Functionality in <Table/> when using Material-UI and React

When using Material-UI's <Table/> with ReactJS, a table is set up with a select all checkbox. Each time an individual row checkbox is clicked, the row id is added to the state array clickedRowIds. This allows for logging of the ids of the clicke ...

What could be causing the error message about jQuery not being defined in this bookmarklet code, even though jQuery is already included

As I work on creating a bookmarklet, I encountered an issue with the code below. When I visit a page, it initially gives an error message saying "jQuery is not defined". However, upon clicking it again, the bookmarklet functions perfectly. var qrcodetog ...

Exporting a module that will return undefined instead of a value

I'm puzzled as to why the exported function findChilds is returning undefined This is how the function appears: const Folder = module.exports = mongoose.model('folder', FolderSchema); module.exports = { findChilds: (folderId) => ...

Developing an animated feature that displays a dynamic count up to the current size of the browser window

I have a script that's able to determine the height and width of my browser window. However, I am facing a challenge in creating a way for these dimensions to count up from zero to their current values upon loading. The desired functionality would be ...