亲爱的,
我遇到了一个我必须解决的问题。我在JavaScript中这样做,但这通常适用于任何语言,并且比其他任何语言更像算法问题。
假设我有一个包含5个值的数组,这些值的TOTAL最终应始终为500 。起始值为100,100,...,100。
好的,现在我希望在这种情况下,我改变一个值,其他值"调整"顺便说一下"总价值" 500保留。并且他们不会按照一些随机的顺序排列,但要保持原来的位置并且"移动"为了平衡,所以保留了它们的原始值(一点点)。
示例:
100 100 100 100 100
我将第一个设置为0 结果应该是:
0 125 125 125 125
现在我将秒设置为0 结果应该是:
31.25 0 156.25 156.25 156.25
我有一个工作原型 - 但我对结果非常不满意。我相信它可以做得更轻松,但我想不出任何。
我附加了我的JS源代码及其完整评论。
以下是一般概念:
INPUT:
- array: of N INT elemnt values
- changed: the index of the element that has been adjusted, this one will be ignored for the array adjustments
- arrayMin / arrayMax: the values that are considered limits for the array elements
- arraySum: defines the sum of the array - this is important to see to what SUM the array has to adjust
PROCESS:
- the array elements minus 1 (the one that is ignored) are counted
- the difference made by the one change of the whole sum is computed
- the difference that has to be made to one and each (except the changed) is computed
- now there is a loop which adds (or subtracts) the difference to each object
- if the object reaches its limits (min or max) nothing can be added or subtracted more and this element will be ingored for the rest computation
- what could not be added to these elements hitting the limit is saved in REST
- at the end the loop checks if there is any REST and if there is, the loops repeats with REST computed among elements that can and may be adjusted further
- NOTE: If the rest is really small - treat it
任何人都应该感兴趣为什么以及我需要什么呢?我在考虑使用四个滑块分享一个"总计"值,您可以根据自己的喜好进行设置,其他人根据更改获取值。
来源: JS source file
**我很开心:) **
谢谢
奥利弗
答案 0 :(得分:2)
如果没有min / max约束,函数可能如下所示:
function reMapArray(array, changed, arraySum) {
const sum = array.reduce( (a, b) => a+b );
const adjust = (sum - arraySum) / (array.length - 1);
return array.map( (a, i) => i === changed ? a : a - adjust );
}
// Demo use
let array = [100, 100, 100, 100, 100];
array[0] = 0;
array = reMapArray(array, 0, 500);
console.log(array.toString());
array[1] = 0;
array = reMapArray(array, 1, 500);
console.log(array.toString());
添加最小/最大验证后,它可能如下所示:
function reMapArray(array, index, minValue, maxValue, arraySum) {
const sum = array.reduce( (a, b) => a+b );
if (sum === arraySum) return array; // end recursion: solution found
const adjust = (arraySum - sum) / array.reduce(
// count the values that can still be modified
(c, a, i) => c + (i === index ? 0
: arraySum > sum ? a < maxValue
: a > minValue),
0);
// apply adjustment, but without getting out of range, and then recurse
return reMapArray(array.map( (a, i) =>
i === index ? a : Math.max(minValue, Math.min(maxValue, a + adjust)) ),
index, minValue, maxValue, arraySum);
}
// Demo use:
let array = [100, 100, 100, 100, 100];
array[0] = 0;
array = reMapArray(array, 0, 0, 150, 500);
console.log(array.toString());
array[1] = 0;
array = reMapArray(array, 1, 0, 150, 500);
console.log(array.toString());
这里第二个输出与第一个解决方案不同,因为最大值已设置为150,因此不允许输出156.25。
答案 1 :(得分:0)
感兴趣的Java解决方案:
public class ArrayAutoAdjuster {
private double[] values = new double[5];
public ArrayAutoAdjuster(){
for(int i = 0; i < values.length; i++){
values[i] = 100;
}
}
public static void main(String args[]){
ArrayAutoAdjuster aaa = new ArrayAutoAdjuster();
aaa.setNewValue(0,0);
System.out.println(aaa.toString());
aaa.setNewValue(1, 0);
System.out.println(aaa.toString());
}
public void setNewValue(int position, double value){
if(values[position] == value){
return;
}
double diff = (values[position] - value)/(values.length-1);
for(int i = 0; i < values.length; i++){
values[i] = i == position ? value : values[i] + diff;
}
}
public String toString(){
String s = "";
for(int i = 0; i < values.length; i++){
s += values[i];
if(i < values.length-1){
s+=",";
}
}
return s;
}
}
答案 2 :(得分:0)
这是一个带有一些日志记录和错误检查的解决方案。
var sum = function(acc, itemValue) { return acc + itemValue; };
var setInitialArray = function(numItems, total) {
console.log("Create array of " + numItems + " items that sum to " + total);
var itemValue = Math.floor(total / numItems);
var extra = total - (numItems * itemValue);
var initArray = Array.apply(null, Array(5)).map(Number.prototype.valueOf, itemValue);
initArray[0] += extra;
return initArray;
};
var adjustArray = function(itemIdx, newValue, items) {
if (!Number.isInteger(itemIdx) || itemIdx < 0 || itemIdx >= items.length) return items;
console.log("Set item " + (itemIdx + 1) + " to " + newValue);
var total = items.reduce(sum, 0),
origItemValue = items[itemIdx],
diffValue = origItemValue - newValue,
totalForRemainItems = total + diffValue,
numItems = items.length - 1;
if (diffValue === 0 || totalForRemainItems < 0) return items;
// make copy of items without the changing item
var newItems = [].concat(items);
newItems.splice(itemIdx, 1);
var itemValue = Math.floor(totalForRemainItems / numItems);
var extra = totalForRemainItems - (numItems * itemValue);
newItems.forEach(function(item, idx) { newItems[idx] = (idx === 0) ? itemValue + extra : itemValue; });
newItems.splice(itemIdx, 0, newValue);
return newItems;
};
var myArray = setInitialArray(5, 502);
console.log(myArray);
var myNewArray = adjustArray(2, 50, myArray);
console.log(myNewArray);