我有一个对象数组,如下所示:
const data = [ // array1
[{x: 1}, {y:2}, {z:3}],
[{x: 1}, {y:2}, {z:3}],
[{x: 1}, {y:2}, {z:3}]
],[ // array2
[{x: 1}, {y:2}, {z:3}],
[{x: 1}, {y:2}, {z:3}],
[{x: 1}, {y:2}, {z:3}]
]
需要完成的工作是将x
与来自array1
的{{1}}的{{1}}的{{1}}相加,这些x
具有相同的索引。 array2
和y
也是如此。最终结果应该是包含求和值的新对象数组。
这样的事情:
z
注意:所有数组的长度相同,如果缺少值,则会替换为[
[{totalXOne: 2}, {totalYOne: 4}, {totalZOne: 6}],
[{totalXTwo: 2}, {totalYTwo: 4}, {totalZTwo: 6}],
[{totalXThree: 2}, {totalYthree: 4}, {totalZThree: 6}],
]
)
我在MDN上找到了一些不错的东西,但是它汇总了所有0
,x
,y
值,并且它返回了单个求和值,如下所示:
z
输出:
let initialValue = 0;
let sum = [{x: 1}, {x:2}, {x:3}].reduce(function(accumulator,currentValue) {
return accumulator + currentValue.x;
}, initialValue)
有什么方法可以实现这个目标吗?
更新
我从其他来源收到[
[{totalX: 3}, {totalY: 6}, {totalZ: 9}], // this is not what I need
]
。它包含一个名为JSON
的属性映射它,我得到必要的allEmpsData
并映射它我得到NET | GROSS | TAX数据。
salaryData
据我所知,一切正常,但事实是,。我不知道更好。然后是魔术:
let allReports = [];
setTimeout(() => {
allEmpsData.map(x => {
let reports = {};
let years = [];
let months = [];
let netArr = [];
let grossArr = [];
let mealArr = [];
let taxArr = [];
let handSalaryArr = [];
x.salaryData.map(y => {
years.push(y.year);
months.push(y.month);
netArr.push(y.totalNetSalary);
grossArr.push(y.bankGrossSalary);
mealArr.push(y.bankHotMeal);
taxArr.push(y.bankContributes);
handSalaryArr.push(y.handSalary);
})
reports.year = years;
reports.month = months;
reports.net = netArr;
reports.gross = grossArr;
reports.meal = mealArr;
reports.taxesData = taxArr;
reports.handSalaryData = handSalaryArr;
allReports.push(Object.assign([], reports));
});
}, 1000);
...它在节点控制台中返回一个空数组,但如果我setTimeout(() => {
result = allReports.reduce((r, a) =>
a.map((b, i) =>
b.map((o, j) =>
Object.assign(...Object
.entries(o)
.map(([k, v]) => ({ [k]: v + (getV(r, [i, j, k]) || 0) }))
)
)
),
undefined
);
console.log(result);
}, 1500);
上面更新的代码中的任何其他属性,它就在那里。有什么建议吗?
答案 0 :(得分:4)
这是一种函数式编程方法,使用中间ES6 Map
:
const data = [[[{x: 1}, {y:2}, {z:3}], [{x: 1}, {y:2}, {z:3}], [{x: 1}, {y:2}, {z:3}]], [[{x: 1}, {y:2}, {z:3}], [{x: 1}, {y:2}, {z:3}],[{x: 1}, {y:2}, {z:3}]]];
const result = data[0].map( (arr, i) => Array.from(data.reduce( (acc, grp) => (
grp[i].forEach( o =>
Object.entries(o).forEach( ([k, v]) => acc.set(k, (acc.get(k) || 0) + v))
), acc
), new Map), ([k, v]) => ({ [k]: v })) );
console.log(result);

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

为了便于解释,我们就某些条款达成一致:
我们有输入(一个数组),由组组成。每个组是一个由行组成的数组。每个行由对象组成,每个对象都有一个属性/值对。
输出没有组级别,但它有行,再次由对象组成,每个都有一个属性/值对。
因此,使用这些条款,我们将通过代码:
由于输出数组中的行数等于任何组中的行数,因此映射第一组的行似乎是一个良好的开端,即像data[0].map
。
对于输出中的每一行,我们需要进行求和,reduce
是该作业的一个很好的候选函数,因此我们调用data.reduce
。对于reduce
调用的初始值,我已经传递了空Map
。目的是用关键和对填充该Map。之后我们可以将Map分解为单独的对象,每个对象只有一个键/和对(但以后就是这样)。
因此reduce
以Map
开头并遍历这些组。我们需要从每个组中取出 i th 行来查找必须添加的对象"。所以我们采取行grp[i]
。
在该行中的每个对象中,我们都使用Object.entries(o)
获取属性名称和值。事实上,该函数返回一个数组,所以我们用forEach
迭代它,知道我们实际上只迭代一次,因为实际上只有一个属性。现在我们有了密钥(k
)和值v
。我们处于输入结构的最深层次。在这里我们调整累加器。
使用acc.get(k)
我们可以知道我们已经为特定密钥累积了什么(例如,对于" x")。如果我们还没有任何东西,那么通过|| 0
将其初始化为0。然后我们将当前值v
添加到其中,并使用acc.set(k, ....)
将该总和存储回地图中。使用逗号运算符,我们将acc
返回到reduce
实现(我们可以在这里使用return
,但逗号运算符更简洁。)
因此Map获得每个键的所有总和。使用Array.from
,我们可以迭代每个键/和对,并使用回调参数将该对转换为适当的小对象(使用{ [k]: v }
)。 [k]
符号在ES6中也是一个新奇事物 - 它允许在对象文字中使用动态密钥名称。
所以... Array.from
返回一个小对象数组,每个对象都有一个总和。该数组表示要输出的一行。 map
方法创建输出中所需的所有行。
答案 1 :(得分:3)
您可以使用辅助函数获取嵌套对象的值,并将值映射到同一索引。
const getV = (o, p) => p.reduce((t, k) => (t || {})[k], o);
var data = [[[{ x: 1 }, { y: 2 }, { z: 3 }], [{ x: 1 }, { y: 2 }, { z: 3 }], [{ x: 1 }, { y: 2 }, { z: 3 }]], [[{ x: 1 }, { y: 2 }, { z: 3 }], [{ x: 1 }, { y: 2 }, { z: 3 }], [{ x: 1 }, { y: 2 }, { z: 3 }]]],
result = data.reduce((r, a) =>
a.map((b, i) =>
b.map((o, j) =>
Object.assign(...Object
.entries(o)
.map(([k, v]) => ({ [k]: v + (getV(r, [i, j, k]) || 0) }))
)
)
),
undefined
);
console.log(result);

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

答案 2 :(得分:2)
尝试以下方法:
var arr1 = [[{x: 1}, {y:2}, {z:3}], [{x: 1}, {y:2}, {z:3}], [{x: 1}, {y:2}, {z:3}]];
var arr2 = [[{x: 1}, {y:2}, {z:3}], [{x: 1}, {y:2}, {z:3}], [{x: 1}, {y:2}, {z:3}]];
var map = {
0 : 'x',
1 : 'y',
2 : 'z'
};
var map2 = {
0 :"One",
1 :"Two",
2 : "Three"
};
var result = [];
var obj= {};
for(var i = 0; i < arr1.length; i++){
total = 0;
var arr =[];
for(var j =0; j < arr1[i].length; j++){
obj["total"+ map[j] + map2[i]] = arr1[i][j][map[j]] + arr2[i][j][map[j]];
arr.push(obj);
obj = {};
}
result.push(arr);
}
console.log(result);
答案 3 :(得分:1)
尝试将这类问题分解为更小的问题并逐步建立起来是一个好主意。这意味着我们不必一次看整件事。
让我们编写一个函数,将数组中的各个元素加在一起:
function addElements(element1, element2, key, rowIndex) {
//for now we keep the keys the same, otherwise multiple additions
//won't work
return {
[key]: element1[key] + element2[key]
};
}
现在,让我们使用addElements()
:
function addRows(row1, row2, rowIndex) {
return ['x', 'y', 'z'].map((key, index) => {
// "key" will go through "x", "y", and "z" as
// "index" goes 0, 1, 2
const element1 = row1[index];
const element2 = row2[index];
return addElements(element1, element2, key, rowIndex);
});
}
现在我们可以迭代第一个矩阵中的所有行,并使用addRows()
从第二个矩阵中添加等价物:
function addMatrices(matrix1, matrix2) {
return matrix1.map((row1, index) => {
const row2 = matrix2[index];
return addRows(row1, row2, index);
});
}
现在我们可以把它变成一个减速器:
const EMPTY_MATRIX = { ... }; //define a matrix of all zeroes here
matrices.reduce(addMatrices, EMPTY_MATRIX);
希望这有帮助!
答案 4 :(得分:1)
试试这个简单的小代码snipet:
const data = [ // array1
[{x: 1}, {y:2}, {z:3}],
[{x: 1}, {y:2}, {z:3}],
[{x: 1}, {y:2}, {z:3}]
],[ // array2
[{x: 1}, {y:2}, {z:3}],
[{x: 1}, {y:2}, {z:3}],
[{x: 1}, {y:2}, {z:3}]
]
var array1 = data[0];
var array2 = data[1];
var returnArray = [];
array1.forEach(function (subArray1, index){
var subArray2 = array2[index];
var subReturn = [];
subArray1.forEach(function (obj, i) {
var variableVal;
if (i == 0){variableVal = "x";} else if (i == 1) {variableVal = "y";}
else if (i == 2) {variableVal = "z"}
var newObj = {};
newObj[variableVal] = obj[variableVal] + subArray2[i][variableVal];
subReturn[i] = newObj;
});
returnArray[index] = subReturn;
});
console.log(returnArray);
答案 5 :(得分:1)
更短的选择:
var data = [ [ [{x: 1}, {y:2}, {z:3}], [{x: 1}, {y:2}, {z:3}], [{x: 1}, {y:2}, {z:3}] ],
[ [{x: 1}, {y:2}, {z:3}], [{x: 1}, {y:2}, {z:3}], [{x: 1}, {y:2}, {z:3}] ] ];
var result = data.reduce( (a, b) => a.map((_, i) =>
Array.from('xyz', (k, j) => [ { [k]: a[i][j][k] + b[i][j][k] } ] ) ) );
console.log( JSON.stringify( result ).replace(/]],/g, ']],\n ') );
答案 6 :(得分:1)
你问的内容基本上称为zipWith
函数。因此,通用解决方案可以作为;
var data = [[[{x: 1}, {y:2}, {z:3}],
[{x: 1}, {y:2}, {z:3}],
[{x: 1}, {y:2}, {z:3}]],
[[{x: 1}, {y:2}, {z:3}],
[{x: 1}, {y:2}, {z:3}],
[{x: 1}, {y:2}, {z:3}]]],
zipWith = (a,b,f) => a.map((e,i) => f(e,b[i])),
zipper = (sa,sb) => sa.map((o,i) => Object.keys(o)
.reduce((r,k) => (r[k] = o[k] + sb[i][k], r), {})),
result = data.reduce((p,c) => zipWith(p,c,zipper));
console.log(result);
&#13;
答案 7 :(得分:0)
此解决方案返回一个对象,每个键的值都相加。
const arr1 = [
[{x: 1}, {y: 2}, {z: 3}],
[{x: 4}, {y: 6}, {z: null}],
[{x: 5}, {y: 7}, {z: 9}]
]
const arr2 = [
[{x: 12}, {y: 20}, {z: 4}],
[{x: 13}, {y: 21}, {z: 3}],
[{x: 14}, {y: 22}, {z: 5}]
]
const arr3 = [
[{x: 2}, {y: 10}, {z: 67}],
[{x: 3}, {y: 31}, {z: 23}],
[{x: null}, {y: 25}, {z: null}]
]
function get_keys (arr) {
let keys = []
for (let i = 0; i < arr[0].length; i++) {
let key = Object.keys(arr[0][i])[0]
keys.push(key)
}
return keys
}
function sum_by_key (arrays) {
let res = {}
let keys = get_keys(arrays)
let all_obj = []
for (let i = 0; i < arrays.length; i++) {
for (let d = 0; d < arrays[i].length; d++) {
all_obj.push(arrays[i][d])
}
}
for (let i = 0; i < keys.length; i++) {
let k = keys[i]
res[k] = 0
for (let d = 0; d < all_obj.length; d++) {
let __k = Object.keys(all_obj[d])[0]
if (k === __k) {
res[k] += all_obj[d][__k]
}
}
}
return res
}
let arrays = [...arr1, ...arr2, ...arr3]
console.log(sum_by_key(arrays)) //=> { x: 54, y: 144, z: 114 }