算法:根据一个数据更改数组的所有值并保持相同的总和

时间:2017-02-09 22:28:31

标签: javascript arrays algorithm

亲爱的,

我遇到了一个我必须解决的问题。我在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

**我很开心:) **

谢谢

奥利弗

3 个答案:

答案 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);