-1

假设我有一个特定的数组:

ary = [0, 1, 2, 4, 5, 6];

这是一个用于范围的数组,其中第一个范围是 0 到 1,第二个范围是 1 到 2,依此类推。该数组的构建使得任何值都不能小于前一个值,但它们可以相等。

第一个和最后一个数组项是静态的,永远不会改变 - 因此范围的总和始终为 6。

function rangeSum(a){
    var sum = 0;
    for(var i = 0; i< a.length-1;i++){
        sum += a[i+1]-a[i];
    }
    return sum; //Always equals 6 with this array
}

现在我想改变一个范围:

ary  = [0, 1, 2, 4, 5, 6];
ary2 = [0, 1, 3, 4, 5, 6]; //Increases the second range with 1, reduces the third range with 1, the rest are unchanged

我想要一个函数,它可以减少第三个范围,并将其均匀地分布在其余范围内,同时保持它们的相互范围大小。

因此,而不是结束:

ary  = [0, 1, 2, 4, 5, 6];       //Range [1, 1, 2,   1,    1]
ary2 = [0, 1, 3, 4, 5, 6];       //Range [1, 2, 1,   1,    1]

我们得到

ary2 = [0, 1, 3, 4.5, 5.25, 6];  //Range [1, 2, 1.5, 0.75, 0.75]

前:

function shiftRange(array, index, increase){
    //Compute new array

    return ary2;
}

ary2 = shiftRange(ary, 2, 1);

该函数应该适用于任何数组大小、任何索引(第一个和最后一个除外)和负数。

这是我试图开始工作的最新代码,但它可能比必要的复杂 - 它根本不起作用:http: //jsfiddle.net/FN6TX/

希望有人可以提供帮助:=)

4

2 回答 2

1

只考虑需要更改的数组部分:

arr = [2, 4, 5, 6]

它从 2 变为 6。您想要转换此数组,以使所有元素彼此具有相同的比例,但从 3 变为 6。

你可以用代数的方式来思考这个问题,原始数据位于笛卡尔图的水平轴上,新数据位于垂直轴上。你肯定知道 2 应该变成 3 (所以你的线(2, 3)在里面),你肯定知道 6 应该保持 6 (所以你的线有(6, 6))。

这条线的方程是

function transform(x) {
    return (6 + 3 * x) / 4;
}

然后,您可以使用以下方法转换数组:

for (var i = 0; i < 4; i++) {
    arr[i] = transform(arr[i]);
}

当然,您可以概括上面的6, 3, 和 (两个不同的) 4s,并调整代码,使其仅在数组的子集上运行。不过,乘法在这种转换方面确实很擅长——只要你想“将某些东西均匀分布”,你就需要乘法。您不必像在小提琴中那样跟踪更改。

更新:安静的早晨,我想:我在http://jsfiddle.net/FN6TX/1/更新了你的小提琴

于 2013-07-04T14:26:21.600 回答
1

这是我带来的解决方案:

var shiftRange = function (array, pos, amount) {

  //First and last position cannot be modified
  if (pos === 0 || pos === array.length-1) return;

  //Generate new array
  var newArray = array.slice();

  var max = array.length;

  //Calculate the modification ratio of the ranges
  var diference = newArray[max - 1] - newArray[pos];
  var newDiference = diference - amount;
  if (newDiference < 0) {
    newDiference = 0;
  }
  var modificationRatio = newDiference / diference;

  //Calculate the range with the previous item
  var ranges = [0];
  var old = null;
  newArray.forEach(function (item) {
    if (old !== null) {
      ranges.push(item - old);
    }
    old = item;

  });

  //Apply the amount
  newArray[pos] =  newArray[max-1] - newDiference;

  //Apply the ratio
  var aux;
  pos++;
  for (; pos < max - 1; pos++) {
    //get pre-increase range
    aux = ranges[pos];
    //calculate new range
    aux = aux * modificationRatio;
    //aply new range to previous value
    newArray[pos] = newArray[pos - 1] + aux;
  }
  return newArray;
};

//examples
var arr = [1,2,4,6,7,8];
alert(shiftRange(arr, 1, 1));
//1,3,4.666666666666667,6.333333333333334,7.166666666666667,8

arr = [0, 1, 2, 4, 5, 6];
alert(shiftRange(arr, 2, 1));
//0,1,3,4.5,5.25,6

arr = [-1, -0.2, 0.5, 0.6, 0.7, 1];
alert(shiftRange(arr, 1, 0.4));
//-1,0.20000000000000007,0.6666666666666667,0.7333333333333334,0.8,1

这是jsfiddle

于 2013-07-04T14:46:22.617 回答