I'm trying to find the simplest way to merge this dynamic array using jQuery.
This is the result I'm getting after trying to use .reduce. The Month/Year object is dynamic, the result is based on the date range.
[
{
"ObjectGroupingId": 1,
"Jan 2022": "Project1",
"Feb 2022": 0,
"Mar 2022": 0,
"Apr 2022": 0,
"May 2022": 0
},
{
"ObjectGroupingId": 1,
"Jan 2022": 0,
"Feb 2022": "Project2",
"Mar 2022": 0,
"Apr 2022": 0,
"May 2022": 0
},
{
"ObjectGroupingId": 1,
"Jan 2022": 0,
"Feb 2022": 0,
"Mar 2022": "Project3",
"Apr 2022": 0,
"May 2022": 0
}
]
What I'm trying to achieve is this
[
{
"ObjectGroupingId": 1,
"Jan 2022": "Project1",
"Feb 2022": "Project2",
"Mar 2022": "Project3"
}
]
This is what I've tried in jQuery
var monthNames = data
.map(function (t) {
var monthName = formatMonthYear(t.dynamicHeaderColumn);
return monthName;
})
.reduce(function (p, t) {
if (p.indexOf(t) == -1)
p.push(t);
return p;
}, []);
// transform
var result = data.reduce(function (p, t) {
var monthName = formatMonthYear(t.dynamicHeaderColumn);
var existing = p.filter(function (t2) {
return t2.objectGroupingId == t.objectGroupingId;
});
if (existing.length) {
existing[0][monthName] = t.projectName;
} else {
var n = {
ObjectGroupingId: t.objectGroupingId
};
monthNames.forEach(function (m) {
n[m] = 0;
});
n[monthName] = t.projectName;
p.push(n);
}
return p;
}, []);
return result;
Is this possible? I'm not quite familiar in jQuery still learning it.
CodePudding user response:
Here is a simple way to achieve this task using a dictionary. I highly recommend you read up on how a dictionary works - they are very useful!
Just a quick explanation of the code, in function(e,d)
the i
is the index and d
is the value. The second - function(key, value)
is a little different. The key
will return the value before the :
instead of an index. This is because you are iterating over the values of an object ({
and }
define the start and end of the object). value
will return anything to the right of the :
.
Update: I have updated the code to allow for any number of ObjectGroups as well as a pure JavaScript version.
var input = [
{
"ObjectGroupingId": 1,
"Jan 2022": "Project1",
"Feb 2022": 0,
"Mar 2022": 0,
"Apr 2022": 0,
"May 2022": 0
},
{
"ObjectGroupingId": 1,
"Jan 2022": 0,
"Feb 2022": "Project2",
"Mar 2022": 0,
"Apr 2022": 0,
"May 2022": 0
},
{
"ObjectGroupingId": 1,
"Jan 2022": 0,
"Feb 2022": 0,
"Mar 2022": "Project3",
"Apr 2022": 0,
"May 2022": 0,
"Jan 1900": 0
},
{
"ObjectGroupingId": 2,
"Jan 2022": 0,
"Feb 2022": 0,
"Mar 2022": 0,
"Apr 2022": 0,
"May 2022": 0,
"Jan 1900": "Project10"
}
]
var currentObjectGrouping = null;
var outputListJQuery = [];
$.each(input, function(i,d){
$.each(d, function(key, value) {
if(key === 'ObjectGroupingId') currentObjectGrouping = value;
if(outputListJQuery[currentObjectGrouping] === undefined) outputListJQuery[currentObjectGrouping] = {};
if(value !== 0) {
outputListJQuery[currentObjectGrouping][key] = value;
}
});
});
outputListJQuery = outputListJQuery.filter(function( element ) {
return element !== undefined;
})
console.log("This is using JQuery!");
console.log(outputListJQuery);
//Pure JavaScript
var outputListJavascript = [];
input.forEach(e => {
for (const [key, value] of Object.entries(e)) {
if(key === 'ObjectGroupingId') currentObjectGrouping = value;
if(outputListJavascript[currentObjectGrouping] === undefined) outputListJavascript[currentObjectGrouping] = {};
if(value !== 0) {
outputListJavascript[currentObjectGrouping][key] = value;
}
}
});
outputListJavascript = outputListJavascript.filter(function( element ) {
return element !== undefined;
})
console.log("This is using only JavaScript!");
console.log(outputListJavascript);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
CodePudding user response:
Why does the OP want to use jQuery? jQuery mainly targets the domain of querying and manipulating the DOM. The OP's task in contrast deals with a single pure data structure and how to traverse/transform it.
Thus the OP should stick to the OP's original approach which uses methods of built-in objects like Array
and Object
.
The next provided code example uses two nested reduce
tasks in order to achieve exactly the OP's desired result ...
function collectGroupedProjectData({ lookup, result }, { ObjectGroupingId, ...restData }) {
let groupedData = lookup[ObjectGroupingId];
if (!groupedData) {
groupedData = lookup[ObjectGroupingId] = { ObjectGroupingId };
result.push(groupedData);
}
Object
.entries(restData)
.reduce((group, [key, value]) => {
if (value !== 0) {
Object.assign(group, { [key]: value });
}
return group;
}, groupedData);
return { lookup, result };
}
const data = [{
ObjectGroupingId: 1,
'Jan 2022': 'Project1',
'Feb 2022': 0,
'Mar 2022': 0,
'Apr 2022': 0,
'May 2022': 0,
}, {
ObjectGroupingId: 1,
'Jan 2022': 0,
'Feb 2022': 'Project2',
'Mar 2022': 0,
'Apr 2022': 0,
'May 2022': 0,
}, {
ObjectGroupingId: 1,
'Jan 2022': 0,
'Feb 2022': 0,
'Mar 2022': 'Project3',
'Apr 2022': 0,
'May 2022': 0,
}, {
ObjectGroupingId: 2,
'Jan 2022': 'Project4',
'Feb 2022': 0,
'Mar 2022': 0,
'Apr 2022': 0,
'May 2022': 0,
}, {
ObjectGroupingId: 2,
'Jan 2022': 0,
'Feb 2022': 'Project5',
'Mar 2022': 0,
'Apr 2022': 0,
'May 2022': 0,
}, {
ObjectGroupingId: 2,
'Jan 2022': 0,
'Feb 2022': 0,
'Mar 2022': 'Project6',
'Apr 2022': 0,
'May 2022': 0,
}];
const listOfGroupedProjects = data
.reduce(collectGroupedProjectData, { lookup: {}, result: [] }).result;
console.log({ listOfGroupedProjects });
.as-console-wrapper { min-height: 100%!important; top: 0; }
CodePudding user response:
In a case where you have multiple ObjectGroupingId
s the final result can be an object of objects where the high-level keys are the ObjectGroupingId
values and the values the aggregated elements.
const data = [{"ObjectGroupingId": 1,"Jan 2022": "Project1","Feb 2022": 0,"Mar 2022": 0,"Apr 2022": 0,"May 2022": 0},{"ObjectGroupingId": 1,"Jan 2022": 0,"Feb 2022": "Project2","Mar 2022": 0,"Apr 2022": 0,"May 2022": 0},{"ObjectGroupingId": 1,"Jan 2022": 0,"Feb 2022": 0,"Mar 2022": "Project3","Apr 2022": 0,"May 2022": 0},{"ObjectGroupingId": 2,"Jan 2022": "Project4","Feb 2022": 0,"Mar 2022": 0,"Apr 2022": 0,"May 2022": 0},{"ObjectGroupingId": 2,"Jan 2022": 0,"Feb 2022": "Project5","Mar 2022": 0,"Apr 2022": 0,"May 2022": 0},{"ObjectGroupingId": 2,"Jan 2022": 0,"Feb 2022": 0,"Mar 2022": "Project6","Apr 2022": 0,"May 2022": 0}];
const aggData = data.reduce((acc, {ObjectGroupingId:id,...rest}) =>
({...acc,[id]:{...acc[id], ...Object.fromEntries(Object.entries(rest).filter(([k,v]) => v !== 0))}}), {}
);
console.log( aggData );