Digamos que hay una matriz de x números, y la suma de ellos es 100.
Cada número aumenta o disminuye linealmente con un paso . Cada vez que un número aumenta el resto tiene que disminuir uniformemente para que la suma de los números no pase de 100. Asimismo cada vez que un número disminuye el resto tiene que aumentar uniformemente para que la suma de los números no baje de 100. Si un valor hace que la suma exceda o baje de 100, la acción debe rechazarse con un mensaje para el usuario.
Digamos que la matriz A: [20,20,20,20,20]
A[2] += 4 //the array A has to become somehow automatically: [19,19,24,19,19]Hay 3 problemas en esto. Primero, si un número excede un valor, eso hará que el resto vaya por debajo de 0, y no quiero eso. Ejemplo:
A: [-5,100,-5,-5,-5]
Y el otro está relacionado con el paso. No sé cuánto debería aumentar o disminuir (tal vez en función de la longitud de la matriz).
Ahora mismo tengo step = 1 / A.length
De modo que si un número aumenta con el paso, el resto debe disminuir con step / A.length - 1 (menos uno porque no cuento el número que cambió el usuario)
Y viceversa
Básicamente, estoy tratando de hacer un incremento o disminución porcentual según el valor del usuario (hacia abajo o hacia arriba). ¿Puedes proponerme la lógica que debo seguir, o algún código JavaScript?
EDITAR:
Ya he implementado algo en angular.
Al principio los valores son todos iguales y la suma es 100:
Si aumento el primer número con el botón ( > ), el resto disminuirá, y así sucesivamente.
No estoy publicando el código porque tiene errores y está muy complicado, solo quiero la lógica o un paradigma en el código para poder implementarlo en mi aplicación. Las casillas de verificación en los números están destinadas a bloquear ese valor para que no aumente ni disminuya.
Puede verificar si hay un valor para disminuir y agregar todos los cambios a la suma para incrementar un valor.
const change = (array, index, direction) => { if (direction === 1) { const step = 1 / array.length; for (let i = 0; i < array.length; i++) { if (i === index || array[i] === 0) continue; const s = Math.min(step, array[i]); array[i] -= s; array[index] += s; } } else { const step = Math.min(1 / array.length, array[index] / (array.length - 1)); for (let i = 0; i < array.length; i++) { if (i === index) continue; array[i] += step; array[index] -= step; } } return array; }, values = [96.8, 0.2, 1, 1, 1], display = values => values.forEach((v, i) => document.getElementById('value' + i).innerHTML = v.toFixed(2)), addEvent = (type, index) => event => { change(values, index, type === 'up' ? 1 : -1); display(values); }; [...document.getElementsByTagName('button')].forEach(element => { const [type, index] = element.id.match(/\d+|\D+/g); element.addEventListener('click', addEvent(type, +index)); }); display(values); .as-console-wrapper { max-height: 100% !important; top: 0; } td { text-align: center; width: 20%; } <table> <tr> <td><button id="up0">^</button></td> <td><button id="up1">^</button></td> <td><button id="up2">^</button></td> <td><button id="up3">^</button></td> <td><button id="up4">^</button></td> </tr> <tr> <td id="value0"></td> <td id="value1"></td> <td id="value2"></td> <td id="value3"></td> <td id="value4"></td> </tr> <tr> <td><button id="down0">v</button></td> <td><button id="down1">v</button></td> <td><button id="down2">v</button></td> <td><button id="down3">v</button></td> <td><button id="down4">v</button></td> </tr> </table>Detalles del ejemplo comentado a continuación
// Utility function const log = data => console.log(JSON.stringify(data)); const arr1 = [20, 20, 20, 20, 20]; const arr2 = [-5, 115, -5, -5]; /**@function *@name incDec *@description Increase/decrease a number by the given index of a given * array by a given number and inversely decrease/increase the rest of * the numbers evenly until the sum of all numbers within the array is * the same as it was originally. *@param {number} index - Index number of the number being changed. *@param {number} by - Number to decrease/increase first parameter by. *@param {array<number>} array - The array of numbers *@returns {array<number>} A new array of modified numbers */ const incDec = (index, by, array) => { /* Chrome doesn't divide negative numbers correctly. Simple divison in of itself needs to be simplified. So a ❉ will denote this as the reason. */ let mod = Math.abs(by); /* Return a new array with the targeted number modified by >by<. */ const newArr = array.map((num, idx) => idx == index ? num + by : num); const div = array.length - 1; //❉ /* Divide the number it changed by, by the number of remaining numbers in the array. */ let quo = mod / div; quo = by < 0 ? -Math.abs(quo) : quo; //❉ // Return a new array that has the modified numbers. return newArr.map((num, idx) => idx == index ? num : num - quo); }; log(incDec(3, 8, arr1)); log(incDec(2, -8, arr2)); .as-console-row::after { width: 0; font-size: 0; } .as-console-row-code { width: 100%; word-break: break-word; }