如何使用forEach列出部分和的清单

时间:2019-03-20 10:47:14

标签: javascript arrays ecmascript-6 foreach

我有一个看起来像这样的数组数组:

changes = [ [1, 1, 1, -1], [1, -1, -1], [1, 1] ];

我想通过添加最后一个值来获取数组中的下一个值

values = [ [1, 2, 3, 2], [1, 0, -1], [1, 2] ];

到目前为止,我已经尝试使用forEach:

changes.forEach(change => {
    let i = changes.indexOf(change);
    let newValue = change[i] + change[i + 1]
});

我认为我做对了,但是我无法采用这种方法工作,或者也许有更好的方法来实现它。

8 个答案:

答案 0 :(得分:23)

您可以保存总和并添加值。

var array = [[1, 1, 1, -1], [1, -1, -1], [1, 1]],
    result = array.map(a => a.map((s => v => s += v)(0)));

console.log(result);

使用forEach,您需要获取对象引用以及前一个值或零。

var array = [[1, 1, 1, -1], [1, -1, -1], [1, 1]];

array.forEach(a => a.forEach((v, i, a) => a[i] = (a[i - 1] || 0) + v));

console.log(array);

答案 1 :(得分:13)

带有map的版本。

const changes = [
  [1, 1, 1, -1],
  [1, -1, -1],
  [1, 1]
];

const values = changes.map(array => {
  let acc = 0;
  return array.map(v => acc += v);
});

console.log(values);
.as-console-wrapper{top:0;max-height:100%!important}

这不会更改源数组。

答案 2 :(得分:4)

生成器的新ESNext功能对此非常有用。

在这里,我已经创建了一个简单的sumpUp生成器,可以重复使用。

function* sumUp(a) {
  let sum = 0;
  for (const v of a) yield sum += v;
}

const changes = [ [1, 1, 1, -1], [1, -1, -1], [1, 1] ];
const values = changes.map(a => [...sumUp(a)]);
  
console.log(values);

答案 3 :(得分:3)

您可以使用Array的map函数

const changes = [ [1, 1, 1, -1], [1, -1, -1], [1, 1] ];    
const result = changes.map((v) => v.slice(0).map((t, i, arr) => i === 0 ? t : (arr[i] += arr[i - 1])))
console.log(changes);
console.log(result);

更新

使用slice克隆数组。这将防止更改原始阵列。

答案 4 :(得分:3)

const changes = [ [1, 1, 1, -1], [1, -1, -1], [1, 1] ]
let values = []
changes.forEach(arr => {
  let accu = 0
  let nestedArr = []
  arr.forEach(n => {
    accu += n
    nestedArr.push(accu)
  })
  values.push(nestedArr)
})
console.log(values)

答案 5 :(得分:2)

另一种方式

您可以使用.map返回具有所需结果的新数组。通过将.reduce与数组作为累加器,可以生成子数组。

var array = [[1, 1, 1, -1], [1, -1, -1], [1, 1]],
    result = array.map(a => a.reduce((ac, v, i) => {
      const lastVal = ac[i-1] || 0;
      return [...ac, lastVal + v];
    }, []));

console.log(result);

// shorter
result = array.map(a => a.reduce((ac, v, i) => [...ac, (ac[i-1] || 0) + v], []));
console.log(result);

答案 6 :(得分:2)

这是遍历数组外部列表的一种更易于阅读的方式。创建内部数组的副本以保留初始值(例如[1、1、1、1 -1])。然后,它将遍历复制数组中的每个值,并将其添加到原始数组中的每个索引之后。

var changes = [[1, 1, 1, -1], [1, -1, -1], [1, 1]];
changes.forEach(subArray => {
    var subArrayCopy = subArray.slice(); 	// Create a copy of the current sub array (i.e. subArrayCopy = [1, 1, 1, -1];)
    subArrayCopy.forEach((val, index) => {	// Iterate through each value in the copy
	for (var i = subArray.length - 1; i > index; i--) { // For each element from the end to the current index
            subArray[i] += val;	 // Add the copy's current index value to the original array
	}
    });
})
console.log(changes);

答案 7 :(得分:0)

您有一个数组数组,但是每个组成数组都与下一个数组无关,因此让我们单独解决它们。让我们来谈谈[1, 1, 1, -1]

您使用的“部分和”一词非常有用。 全额可以使用reduce来实现:

[1, 1, 1, -1].reduce((x, y) => x + y);
// 2

但是您需要一个部分和数组。这与reduce的用法非常相似,但是我们不仅保留了最后的计算结果,还保留了每个中间值。在其他语言中,这称为scan(参见F#Haskell)。

通用scan的javascript实现看起来很像reduce。实际上,您可以使用reduce来实现它,而只需做一些额外的工作:

function scan(array, callback) {
  const results = [array[0]];

  // reduce does all the heavy lifting for us, but we define a wrapper to pass to it.
  array.reduce((...args) => {
    // The wrapper forwards all those arguments to the callback, but captures the result...
    const result = callback(...args);
    // ...storing that intermediate result in our results array...
    results.push(result);
    // ...then passes it back to reduce to continue what it was doing.
    return result;
  });

  return results;
}

// scan([1, 1, 1, -1], (x, y) => x + y) -> [1, 2, 3, 2]

更健壮的实现会更接近于标准库的reduce,尤其是在初始值附近:

function scan(array, callback, initialValue) {
  const results = [];

  const reducer = (...args) => {
    const result = callback(...args);
    results.push(result);
    return result;
  };

  if (arguments.length === 2) {
    results.push(array[0]);
    array.reduce(reducer);
  } else {
    results.push(initialValue);
    array.reduce(reducer, initialValue);
  }

  return results;
}

将其重新组合在一起,如果您要对数组数组执行此操作,那么它就只是map上的scan

[[1, 1, 1, -1], [1, -1, -1], [1, 1]].map(a => scan(a, (x, y) => x + y));
// [[1, 2, 3, 2], [1, 0, -1], [1, 2]]

无需复制,也无需注意副作用,因此您可以从中获得方便的高阶功能来启动!