使用 reduce 的数组输出的特定键的累积和
Cumulative sum of specific keys with array output using reduce
假设我有以下数组:
let arr = [{a: 1, b: 2}, {a: 2, b: 4}, {a: 8, b: -1}]
我想计算每个键的累计和,但我也希望输出是一个长度相同的数组,每一步都有累计值。最后的结果应该是:
[{a: 1, b: 2}, {a: 3, b: 6}, {a: 11, b: 5}]
我的问题是我无法获得所需的数组。我只得到最终的对象:
let result = arr.reduce((accumulator, element) => {
if(accumulator.length === 0) {
accumulator = element
} else {
for(let i in element){
accumulator[i] = accumulator[i] + element[i]
}
}
return accumulator
}, [])
console.log(result); // {a: 11, b: 5}
像这样:
const arr = [{a: 1, b: 2}, {a: 2, b: 4}, {a: 8, b: -1}]
const result = arr.reduce((accumulator, element, index) => {
if(accumulator.length === 0) {
accumulator.push(element)
} else {
const sum = {};
for(let i in element) {
sum[i] = element[i] + (accumulator[index - 1][i] || 0)
}
accumulator.push(sum)
}
return accumulator
}, [])
console.log(result);
另一个选项是使用 Map
保持总和结果,如果数组元素中的键不总是相同,它会有所帮助。
const arr = [{a: 1, b: 2}, {a: 2}, {a: 8, b: -1}];
const map = new Map();
const result = arr.map((element) => {
const sum = {};
for (let i in element) {
sum[i]= element[i] + (map.get(i) || 0);
map.set(i, sum[i]);
}
return sum;
});
console.log(result);
这里有一些更简洁的 reduce,结果可能不那么可读...
array.reduce((y,x,i) => ( i===0 ? y : [...y, {a: x.a + y[i-1].a, b: x.b + y[i-1].b}]),[array[0]])
let array = [{a: 1, b: 2}, {a: 2, b: 4}, {a: 8, b: -1}]
let culm = array.reduce((y,x,i) => ( i===0 ? y : [...y, {a: x.a + y[i-1].a, b: x.b + y[i-1].b}]),[array[0]])
console.log(culm)
您可以使用 reduce
as
轻松实现结果
let arr = [
{ a: 1, b: 2 },
{ a: 2, b: 4 },
{ a: 8, b: -1 },
];
const result = arr.reduce((acc, curr, i) => {
if (i === 0) acc.push(curr);
else {
const last = acc[i - 1];
const newObj = {};
Object.keys(curr).forEach((k) => (newObj[k] = curr[k] + last[k]));
acc.push(newObj);
}
return acc;
}, []);
console.log(result);
你想要的听起来像 scan()
高阶函数(借用 ramda.js 的想法),它允许你 return 每个元素的累积结果你的阵列。 scan 方法类似于 .reduce()
方法的行为方式,不同之处在于它 return 是每个元素的累加器。您可以像这样自己构建 scan()
函数:
let arr = [{a: 1, b: 2}, {a: 2, b: 4}, {a: 8, b: -1}];
const scan = ([x, ...xs], fn) => xs.reduce((acc, elem) => {
return [...acc, fn(acc.at(-1), elem)];
}, xs.length ? [x] : []);
const res = scan(arr, (x, y) => ({a: x.a+y.a, b: x.b+y.b}));
console.log(res);
您可能会考虑进一步改进,例如为扫描方法提供初始值(类似于 reduce 接受一个值的方式)。此外,如果您需要更好的浏览器支持,.at()
方法目前的浏览器支持有限,因此您可以考虑创建自己的 at()
函数:
const at = (arr, idx) => idx >= 0 ? arr[idx] : arr[arr.length + idx];
鉴于:
const xs =
[ {a: 1, b: 2}
, {a: 2, b: 4}
, {a: 8, b: -1}];
定义一个函数sum
例如:
const sum = ([head, ...tail]) =>
tail.reduce((x, y) =>
({a: (x.a+y.a), b: (x.b+y.b)}), head);
sum(xs);
//=> {a: 11, b: 5}
然后在 xs
的较大切片上的映射中应用该函数:
xs.map((_, i, arr) => sum(arr.slice(0, i+1)));
//=> [ {a: 1, b: 2}
//=> , {a: 3, b: 6}
//=> , {a: 11, b: 5}]
假设我有以下数组:
let arr = [{a: 1, b: 2}, {a: 2, b: 4}, {a: 8, b: -1}]
我想计算每个键的累计和,但我也希望输出是一个长度相同的数组,每一步都有累计值。最后的结果应该是:
[{a: 1, b: 2}, {a: 3, b: 6}, {a: 11, b: 5}]
我的问题是我无法获得所需的数组。我只得到最终的对象:
let result = arr.reduce((accumulator, element) => {
if(accumulator.length === 0) {
accumulator = element
} else {
for(let i in element){
accumulator[i] = accumulator[i] + element[i]
}
}
return accumulator
}, [])
console.log(result); // {a: 11, b: 5}
像这样:
const arr = [{a: 1, b: 2}, {a: 2, b: 4}, {a: 8, b: -1}]
const result = arr.reduce((accumulator, element, index) => {
if(accumulator.length === 0) {
accumulator.push(element)
} else {
const sum = {};
for(let i in element) {
sum[i] = element[i] + (accumulator[index - 1][i] || 0)
}
accumulator.push(sum)
}
return accumulator
}, [])
console.log(result);
另一个选项是使用 Map
保持总和结果,如果数组元素中的键不总是相同,它会有所帮助。
const arr = [{a: 1, b: 2}, {a: 2}, {a: 8, b: -1}];
const map = new Map();
const result = arr.map((element) => {
const sum = {};
for (let i in element) {
sum[i]= element[i] + (map.get(i) || 0);
map.set(i, sum[i]);
}
return sum;
});
console.log(result);
这里有一些更简洁的 reduce,结果可能不那么可读...
array.reduce((y,x,i) => ( i===0 ? y : [...y, {a: x.a + y[i-1].a, b: x.b + y[i-1].b}]),[array[0]])
let array = [{a: 1, b: 2}, {a: 2, b: 4}, {a: 8, b: -1}]
let culm = array.reduce((y,x,i) => ( i===0 ? y : [...y, {a: x.a + y[i-1].a, b: x.b + y[i-1].b}]),[array[0]])
console.log(culm)
您可以使用 reduce
as
let arr = [
{ a: 1, b: 2 },
{ a: 2, b: 4 },
{ a: 8, b: -1 },
];
const result = arr.reduce((acc, curr, i) => {
if (i === 0) acc.push(curr);
else {
const last = acc[i - 1];
const newObj = {};
Object.keys(curr).forEach((k) => (newObj[k] = curr[k] + last[k]));
acc.push(newObj);
}
return acc;
}, []);
console.log(result);
你想要的听起来像 scan()
高阶函数(借用 ramda.js 的想法),它允许你 return 每个元素的累积结果你的阵列。 scan 方法类似于 .reduce()
方法的行为方式,不同之处在于它 return 是每个元素的累加器。您可以像这样自己构建 scan()
函数:
let arr = [{a: 1, b: 2}, {a: 2, b: 4}, {a: 8, b: -1}];
const scan = ([x, ...xs], fn) => xs.reduce((acc, elem) => {
return [...acc, fn(acc.at(-1), elem)];
}, xs.length ? [x] : []);
const res = scan(arr, (x, y) => ({a: x.a+y.a, b: x.b+y.b}));
console.log(res);
您可能会考虑进一步改进,例如为扫描方法提供初始值(类似于 reduce 接受一个值的方式)。此外,如果您需要更好的浏览器支持,.at()
方法目前的浏览器支持有限,因此您可以考虑创建自己的 at()
函数:
const at = (arr, idx) => idx >= 0 ? arr[idx] : arr[arr.length + idx];
鉴于:
const xs =
[ {a: 1, b: 2}
, {a: 2, b: 4}
, {a: 8, b: -1}];
定义一个函数sum
例如:
const sum = ([head, ...tail]) =>
tail.reduce((x, y) =>
({a: (x.a+y.a), b: (x.b+y.b)}), head);
sum(xs);
//=> {a: 11, b: 5}
然后在 xs
的较大切片上的映射中应用该函数:
xs.map((_, i, arr) => sum(arr.slice(0, i+1)));
//=> [ {a: 1, b: 2}
//=> , {a: 3, b: 6}
//=> , {a: 11, b: 5}]