使用动态键合并和求和对象数组
Merge and sum array of objects with dynamic keys
我有一个对象数组的数据结构,其中包含为以下多个不同角色花费的小时数:
[{"week 01" : {"Developer" : 1}},
{"week 01" : {"Project Manager" : 5}},
{"week 01" : {"Project Manager" : 6}},
{"week 01": {"Developer" : 8}},
{"week 02" : {"Strategy" : 4}}]
角色和周数是动态的(即我事先不知道 key/values),我想对同一角色和同一周的所有时间求和以获得以下输出:
[{"week 01" : {
"Developer" : 9
"Project Manager" : 11
}
},
{"week 02" : {
"Strategy" : 4
}
}]
我试过使用 reduce
函数,但似乎不太对劲:
function reduceArray(arr) {
const result = arr.reduce((result, item) => {
let obj = {};
const existing = result.find(function (x) {
for (var prop in x) {
if (x[prop] === item[prop]) {
//same week number found
//loop through roles
for (var subProp in x[prop]) {
if (x[prop][subProp] === item[prop][subProp]) {
obj[prop][subProp] += x[prop][subProp] + item[prop][subProp]
//This is where I lose myself in the prop-loops....
}
}
}
}
})
}, [])
return result;
}
您可以使用所有类型的累积值生成单个对象。
const
data = [{ "week 01": { Developer: 1 } }, { "week 01": { "Project Manager": 5 } }, { "week 01": { "Project Manager" : 6 } }, { "week 01": { Developer : 8 } }, { "week 02": { Strategy: 4 } }],
result = data.reduce((r, o) => {
Object
.entries(o)
.forEach(([week, q]) => Object
.entries(q)
.forEach(([type, value]) => {
(r[week] ??= {})[type] ??= 0;
r[week][type] += value;
})
);
return r;
}, {});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
const data = [
{ "week 01": { Developer: 1 } },
{ "week 01": { "Project Manager": 5 } },
{ "week 01": { "Project Manager": 6 } },
{ "week 01": { Developer: 8 } },
{ "week 02": { Strategy: 4 } },
];
const result = data.reduce(
(prev, item) => {
for (const week in item) {
if (prev[week]) {
for (const act in item[week]) {
if (prev[week][act]) {
prev[week][act] += item[week][act];
} else {
prev[week][act] = item[week][act];
}
}
} else {
prev[week] = item[week];
}
}
return prev;
},
{}
);
console.log(result);
我会使用反射和嵌套循环而不是 reduce。
const weeks = {};
for(let cell of array){
//Assumes your cells will only have one key and that key is a week
for(let key in Object.keys(cell)){
if(!weeks[key]){
weeks[key] = {};
}
//Similiar assumption here
for(let role in Object.keys(cell[key])){
weeks[key][role] = (weeks[key][role] ? weeks[key][role] : 0) + cell[key][role];
}
}
}
使用嵌套循环。在纯 javascript 你可能会得到类似
const data = [{ "week 01": { "Developer": 1 } },
{ "week 01": { "Project Manager": 5 } },
{ "week 01": { "Project Manager": 6 } },
{ "week 01": { "Developer": 8 } },
{ "week 02": { "Strategy": 4 } }];
function getTotalHoursPerRole(data) {
let totalHoursPerRole = [];
for (let i = 0; i < data.length; i++) {
for (let week in data[i]) {
let roleWithHour = data[i][week];
for (let role in roleWithHour) {
if (!totalHoursPerRole[week]) totalHoursPerRole[week] = {};
if (!totalHoursPerRole[week][role]) totalHoursPerRole[week][role] = 0;
totalHoursPerRole[week][role] += roleWithHour[role];
}
}
}
return totalHoursPerRole;
}
console.log(getTotalHoursPerRole(data));
这是一个简单的方法。希望评论有用。
const data = [
{ "week 01": { Developer: 1 } },
{ "week 01": { "Project Manager": 5 } },
{ "week 01": { "Project Manager": 6 } },
{ "week 01": { Developer: 8 } },
{ "week 02": { Strategy: 4 } }
];
function cleanUp(data) {
return data.reduce((acc, item) => {
// assign variables
const week = Object.keys(item).pop();
const [job, value] = Object.entries(item[week]).pop();
// initialise them, if they aren't in the accumilator.
if (!acc[week]) acc[week] = {};
if (!acc[week][job]) acc[week][job] = 0;
// add the value
acc[week][job] += value;
return acc;
}, {});
}
console.log(cleanUp(data));
这是一个使用 for...in
而不是 Object.keys()
和 Object.entries()
,
const data = [
{ "week 01": { Developer: 1 } },
{ "week 01": { "Project Manager": 5 } },
{ "week 01": { "Project Manager": 6 } },
{ "week 01": { Developer: 8 } },
{ "week 02": { Strategy: 4 } }
];
function cleanUp(data) {
return data.reduce((acc, item) => {
for (const week in item) {
if (!acc[week]) acc[week] = {};
for (const job in item[week]) {
if (!acc[week][job]) acc[week][job] = 0;
acc[week][job] += item[week][job];
}
}
return acc;
}, {});
}
console.log(cleanUp(data));
按周数分组,然后按工作名称对每个周数分组并求和。
const arr = [
{ "week 01": { Developer: 1 } },
{ "week 01": { "Project Manager": 5 } },
{ "week 01": { "Project Manager": 6 } },
{ "week 01": { Developer: 8 } },
{ "week 02": { Strategy: 4 } },
];
// First group By weeks num:
function groupByWeekNum(weeksArray) {
return weeksArray.reduce((weeks, currWeek) => {
const weekNum = Object.entries(currWeek)[0][0];
weeks[weekNum] ??= [];
weeks[weekNum].push(currWeek);
return weeks;
}, {});
}
结果为:
{
"week 01": [
{
"week 01": {
"Developer": 1
}
},
{
"week 01": {
"Project Manager": 5
}
},
{
"week 01": {
"Project Manager": 6
}
},
{
"week 01": {
"Developer": 8
}
}
],
"week 02": [
{
"week 02": {
"Strategy": 4
}
}
]
}
然后每组week,按Job分组,累加每个job.Developer
的值
function groupByWeekJob(jobsArr) {
const grouping = jobsArr.reduce((jobs, currJob) => {
const jobName = Object.entries(currJob)[0][0];
const jobValue = Object.entries(currJob)[0][1];
jobs[jobName] ??= 0;
if (jobName in jobs) {
jobs[jobName] += jobValue;
} else {
jobs[jobName] = jobValue;
}
return jobs;
}, {});
return grouping;
}
调用函数:
const res = Object.entries(groupByWeekNum(arr)).map(([week, weekJobs]) =>
groupByWeekJob(weekJobs.map((week) => Object.entries(week)[0][1]))
);
的结果console.log(res, null, 4);
:
[
{
"Developer": 9,
"Project Manager": 11
},
{
"Strategy": 4
}
]
如果每个条目只有一个(参见第二个[0]
)角色,您可以使用以下内容:
const summary = work.reduce((acc,cur) => {
let [week, val] = Object.entries(cur)[0];
let [role, hours] = Object.entries(val)[0];
acc[week] = acc[week] || {};
acc[week][role] = (acc[week][role] || 0) + hours;
return acc;
},{});
/* OUTPUT:
{
"week 01": {
"Developer": 9,
"Project Manager": 11
},
"week 02": {
"Strategy": 4
}
}
*/
演示
const work = [{"week 01" : {"Developer" : 1}},
{"week 01" : {"Project Manager" : 5}},
{"week 01" : {"Project Manager" : 6}},
{"week 01": {"Developer" : 8}},
{"week 02" : {"Strategy" : 4}}]
const summary = work.reduce((acc,cur) => {
let [week, val] = Object.entries(cur)[0];
let [role, hours] = Object.entries(val)[0];
acc[week] = acc[week] || {};
acc[week][role] = (acc[week][role] || 0) + hours;
return acc;
},{});
console.log(summary);
//To convert summary into an array of objects
const arrsum = Object.entries(summary)
.map(entry => Object.fromEntries([entry]));
console.log( arrsum );
要将输出转换为对象数组,请使用以下代码:
const arrsum = Object.entries(summary)
.map(entry => Object.fromEntries([entry]));
我有一个对象数组的数据结构,其中包含为以下多个不同角色花费的小时数:
[{"week 01" : {"Developer" : 1}},
{"week 01" : {"Project Manager" : 5}},
{"week 01" : {"Project Manager" : 6}},
{"week 01": {"Developer" : 8}},
{"week 02" : {"Strategy" : 4}}]
角色和周数是动态的(即我事先不知道 key/values),我想对同一角色和同一周的所有时间求和以获得以下输出:
[{"week 01" : {
"Developer" : 9
"Project Manager" : 11
}
},
{"week 02" : {
"Strategy" : 4
}
}]
我试过使用 reduce
函数,但似乎不太对劲:
function reduceArray(arr) {
const result = arr.reduce((result, item) => {
let obj = {};
const existing = result.find(function (x) {
for (var prop in x) {
if (x[prop] === item[prop]) {
//same week number found
//loop through roles
for (var subProp in x[prop]) {
if (x[prop][subProp] === item[prop][subProp]) {
obj[prop][subProp] += x[prop][subProp] + item[prop][subProp]
//This is where I lose myself in the prop-loops....
}
}
}
}
})
}, [])
return result;
}
您可以使用所有类型的累积值生成单个对象。
const
data = [{ "week 01": { Developer: 1 } }, { "week 01": { "Project Manager": 5 } }, { "week 01": { "Project Manager" : 6 } }, { "week 01": { Developer : 8 } }, { "week 02": { Strategy: 4 } }],
result = data.reduce((r, o) => {
Object
.entries(o)
.forEach(([week, q]) => Object
.entries(q)
.forEach(([type, value]) => {
(r[week] ??= {})[type] ??= 0;
r[week][type] += value;
})
);
return r;
}, {});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
const data = [
{ "week 01": { Developer: 1 } },
{ "week 01": { "Project Manager": 5 } },
{ "week 01": { "Project Manager": 6 } },
{ "week 01": { Developer: 8 } },
{ "week 02": { Strategy: 4 } },
];
const result = data.reduce(
(prev, item) => {
for (const week in item) {
if (prev[week]) {
for (const act in item[week]) {
if (prev[week][act]) {
prev[week][act] += item[week][act];
} else {
prev[week][act] = item[week][act];
}
}
} else {
prev[week] = item[week];
}
}
return prev;
},
{}
);
console.log(result);
我会使用反射和嵌套循环而不是 reduce。
const weeks = {};
for(let cell of array){
//Assumes your cells will only have one key and that key is a week
for(let key in Object.keys(cell)){
if(!weeks[key]){
weeks[key] = {};
}
//Similiar assumption here
for(let role in Object.keys(cell[key])){
weeks[key][role] = (weeks[key][role] ? weeks[key][role] : 0) + cell[key][role];
}
}
}
使用嵌套循环。在纯 javascript 你可能会得到类似
const data = [{ "week 01": { "Developer": 1 } },
{ "week 01": { "Project Manager": 5 } },
{ "week 01": { "Project Manager": 6 } },
{ "week 01": { "Developer": 8 } },
{ "week 02": { "Strategy": 4 } }];
function getTotalHoursPerRole(data) {
let totalHoursPerRole = [];
for (let i = 0; i < data.length; i++) {
for (let week in data[i]) {
let roleWithHour = data[i][week];
for (let role in roleWithHour) {
if (!totalHoursPerRole[week]) totalHoursPerRole[week] = {};
if (!totalHoursPerRole[week][role]) totalHoursPerRole[week][role] = 0;
totalHoursPerRole[week][role] += roleWithHour[role];
}
}
}
return totalHoursPerRole;
}
console.log(getTotalHoursPerRole(data));
这是一个简单的方法。希望评论有用。
const data = [
{ "week 01": { Developer: 1 } },
{ "week 01": { "Project Manager": 5 } },
{ "week 01": { "Project Manager": 6 } },
{ "week 01": { Developer: 8 } },
{ "week 02": { Strategy: 4 } }
];
function cleanUp(data) {
return data.reduce((acc, item) => {
// assign variables
const week = Object.keys(item).pop();
const [job, value] = Object.entries(item[week]).pop();
// initialise them, if they aren't in the accumilator.
if (!acc[week]) acc[week] = {};
if (!acc[week][job]) acc[week][job] = 0;
// add the value
acc[week][job] += value;
return acc;
}, {});
}
console.log(cleanUp(data));
这是一个使用 for...in
而不是 Object.keys()
和 Object.entries()
,
const data = [
{ "week 01": { Developer: 1 } },
{ "week 01": { "Project Manager": 5 } },
{ "week 01": { "Project Manager": 6 } },
{ "week 01": { Developer: 8 } },
{ "week 02": { Strategy: 4 } }
];
function cleanUp(data) {
return data.reduce((acc, item) => {
for (const week in item) {
if (!acc[week]) acc[week] = {};
for (const job in item[week]) {
if (!acc[week][job]) acc[week][job] = 0;
acc[week][job] += item[week][job];
}
}
return acc;
}, {});
}
console.log(cleanUp(data));
按周数分组,然后按工作名称对每个周数分组并求和。
const arr = [
{ "week 01": { Developer: 1 } },
{ "week 01": { "Project Manager": 5 } },
{ "week 01": { "Project Manager": 6 } },
{ "week 01": { Developer: 8 } },
{ "week 02": { Strategy: 4 } },
];
// First group By weeks num:
function groupByWeekNum(weeksArray) {
return weeksArray.reduce((weeks, currWeek) => {
const weekNum = Object.entries(currWeek)[0][0];
weeks[weekNum] ??= [];
weeks[weekNum].push(currWeek);
return weeks;
}, {});
}
结果为:
{
"week 01": [
{
"week 01": {
"Developer": 1
}
},
{
"week 01": {
"Project Manager": 5
}
},
{
"week 01": {
"Project Manager": 6
}
},
{
"week 01": {
"Developer": 8
}
}
],
"week 02": [
{
"week 02": {
"Strategy": 4
}
}
]
}
然后每组week,按Job分组,累加每个job.Developer
的值function groupByWeekJob(jobsArr) {
const grouping = jobsArr.reduce((jobs, currJob) => {
const jobName = Object.entries(currJob)[0][0];
const jobValue = Object.entries(currJob)[0][1];
jobs[jobName] ??= 0;
if (jobName in jobs) {
jobs[jobName] += jobValue;
} else {
jobs[jobName] = jobValue;
}
return jobs;
}, {});
return grouping;
}
调用函数:
const res = Object.entries(groupByWeekNum(arr)).map(([week, weekJobs]) =>
groupByWeekJob(weekJobs.map((week) => Object.entries(week)[0][1]))
);
的结果console.log(res, null, 4);
:
[
{
"Developer": 9,
"Project Manager": 11
},
{
"Strategy": 4
}
]
如果每个条目只有一个(参见第二个[0]
)角色,您可以使用以下内容:
const summary = work.reduce((acc,cur) => {
let [week, val] = Object.entries(cur)[0];
let [role, hours] = Object.entries(val)[0];
acc[week] = acc[week] || {};
acc[week][role] = (acc[week][role] || 0) + hours;
return acc;
},{});
/* OUTPUT:
{
"week 01": {
"Developer": 9,
"Project Manager": 11
},
"week 02": {
"Strategy": 4
}
}
*/
演示
const work = [{"week 01" : {"Developer" : 1}},
{"week 01" : {"Project Manager" : 5}},
{"week 01" : {"Project Manager" : 6}},
{"week 01": {"Developer" : 8}},
{"week 02" : {"Strategy" : 4}}]
const summary = work.reduce((acc,cur) => {
let [week, val] = Object.entries(cur)[0];
let [role, hours] = Object.entries(val)[0];
acc[week] = acc[week] || {};
acc[week][role] = (acc[week][role] || 0) + hours;
return acc;
},{});
console.log(summary);
//To convert summary into an array of objects
const arrsum = Object.entries(summary)
.map(entry => Object.fromEntries([entry]));
console.log( arrsum );
要将输出转换为对象数组,请使用以下代码:
const arrsum = Object.entries(summary)
.map(entry => Object.fromEntries([entry]));