增加或减少数组的数量,使它们的总和始终保持 100
Increase or decrease numbers of an array so the sum of them always remains 100
假设有一个 x 数数组,它们的和是 100。
每个数字增加或减少线性 step。每当一个数字增加时,其余的数字必须减少 均匀地 ,以便数字的总和不超过 100。同样,每当一个数字减少时,其余的数字必须增加 均匀地 以便数字的总和不会低于 100。如果某个值导致总和超过或低于 100,则必须禁止该操作并向用户发送消息。
假设数组 A: [20,20,20,20,20]
A[2] += 4
//the array A has to become somehow automatically: [19,19,24,19,19]
这个有3个问题。首先,如果一个数字超过了一个值,那将使其余数字低于 0,我不希望这样。示例:
A: [-5,100,-5,-5,-5]
还有一个跟步骤有关。我不知道应该增加或减少多少(可能基于数组的长度)。
现在我有step = 1 / A.length
因此,如果一个数字随着 step 增加,则其余数字
必须减少step / A.length - 1
(减去一个因为我没有计算用户更改的数量)
反之亦然
基本上我试图根据用户价值(向下或向上)进行百分比增加或减少。
你能给我建议我必须遵循的逻辑,或者一些 JavaScript 代码吗?
编辑:
我已经在 angular 中实现了一些东西。
起初所有值都相等,总和为 100:
如果我使用按钮 ( > ) 增加第一个数字,其余数字将减少,依此类推..
我没有发布代码,因为它有错误并且非常紧密,我只想要代码中的逻辑或范例,以便我可以在我的应用程序中实现它。数字中的复选框旨在锁定该值,因此它不会增加或减少。
您可以检查是否有递减值并将所有更改添加到总和以递增值。
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>
下面的详细评论示例
// 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;
}
假设有一个 x 数数组,它们的和是 100。
每个数字增加或减少线性 step。每当一个数字增加时,其余的数字必须减少 均匀地 ,以便数字的总和不超过 100。同样,每当一个数字减少时,其余的数字必须增加 均匀地 以便数字的总和不会低于 100。如果某个值导致总和超过或低于 100,则必须禁止该操作并向用户发送消息。
假设数组 A: [20,20,20,20,20]
A[2] += 4
//the array A has to become somehow automatically: [19,19,24,19,19]
这个有3个问题。首先,如果一个数字超过了一个值,那将使其余数字低于 0,我不希望这样。示例:
A: [-5,100,-5,-5,-5]
还有一个跟步骤有关。我不知道应该增加或减少多少(可能基于数组的长度)。
现在我有step = 1 / A.length
因此,如果一个数字随着 step 增加,则其余数字
必须减少step / A.length - 1
(减去一个因为我没有计算用户更改的数量)
反之亦然
基本上我试图根据用户价值(向下或向上)进行百分比增加或减少。 你能给我建议我必须遵循的逻辑,或者一些 JavaScript 代码吗?
编辑:
我已经在 angular 中实现了一些东西。
起初所有值都相等,总和为 100:
如果我使用按钮 ( > ) 增加第一个数字,其余数字将减少,依此类推..
我没有发布代码,因为它有错误并且非常紧密,我只想要代码中的逻辑或范例,以便我可以在我的应用程序中实现它。数字中的复选框旨在锁定该值,因此它不会增加或减少。
您可以检查是否有递减值并将所有更改添加到总和以递增值。
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>
下面的详细评论示例
// 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;
}