Reputation: 53
I have this array of objects, that I need to modify to make the rendering easier . I used some code mentioned in a similar question : Group array of object nesting some of the keys with specific names
Here's my array and code
function groupAndMap(events, Year, Month, predic){
return _.map(_.groupBy(events,Year), (obj,key) => ({
[Year]: key,
[Month]: (predic && predic(obj)) || obj
}));
}
const items = [
{
"Year": 2018,
"Month": 7,
"Day": 2,
"Title": "event1",
"StartDate": "2018-07-02T10:00:00.000Z",
"EndDate": "2018-07-02T11:00:00.000Z"
}, {
"Year": 2018,
"Month": 8,
"Day": 31,
"Title": "event2",
"StartDate": "2018-07-31T10:00:00.000Z",
"EndDate": "2018-08-02T11:00:00.000Z"
}
];
function groupAndMap(items, itemKey, childKey, predic){
return _.map(_.groupBy(items,itemKey), (obj,key) => ({
[itemKey]: key,
[childKey]: (predic && predic(obj)) || obj
}));
}
var result = groupAndMap(items,"Year","Months",
arr => groupAndMap(arr,"Month", "Days"));
var jsonvalue = JSON.stringify(result);
document.write(jsonvalue);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.js"></script>
I want my output to be in the following format
[{
"Year": "2019",
"Months": [{
"Month": "8",
"Days": [{
"Day": "31",
"Events": [{
"Year": 2019,
"Month": 8,
"Day": 31,
"Title": "event3",
"StartDate": "2018-07-31T10:00:00.000Z",
"EndDate": "2018-08-02T11:00:00.000Z"
}]
}]
}]
}]
How should i modify the code in order to get this result ?
Upvotes: 4
Views: 270
Reputation: 386654
You could use an array with the keys to group for the nested objects.
function groupAndMap(events, groups) {
return _(events)
.groupBy(groups[0])
.map((array, key) => ({
[groups[0]]: key,
[groups[1] + 's']: groups[2] && groupAndMap(array, groups.slice(1)) || array
}))
.values();
}
var items = [{ Year: 2018, Month: 7, Day: 2, Title: "event1", StartDate: "2018-07-02T10:00:00.000Z", EndDate: "2018-07-02T11:00:00.000Z" }, { Year: 2018, Month: 8, Day: 31, Title: "event2", StartDate: "2018-07-31T10:00:00.000Z", EndDate: "2018-08-02T11:00:00.000Z" }],
result = groupAndMap(items, ["Year", "Month", "Day", "Event"]);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.js"></script>
With defined keys for the result
function groupAndMap(events, groups, keys) {
return _(events)
.groupBy(groups[0])
.map((array, key) => ({
[groups[0]]: key,
[groups[1] + 's']: groups[2] && groupAndMap(array, groups.slice(1), keys) || _.map(array, o => _.pick(o, keys))
}))
.values();
}
var items = [{ Year: 2018, Month: 7, Day: 2, Title: "event1", StartDate: "2018-07-02T10:00:00.000Z", EndDate: "2018-07-02T11:00:00.000Z" }, { Year: 2018, Month: 8, Day: 31, Title: "event2", StartDate: "2018-07-31T10:00:00.000Z", EndDate: "2018-08-02T11:00:00.000Z" }],
result = groupAndMap(items, ["Year", "Month", "Day", "Event"], ['Title', 'StartDate', 'EndDate']);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.js"></script>
Upvotes: 1
Reputation: 138297
I think its the easiest if you group by an array of criterias:
const entries = Symbol.for("entries");
const tree = { [entries]: [] };
const groups = ["Year", "Month", "Day"];
const childNames = ["Months", "Days", "Events"];
for(const item of items) {
let node = tree;
for(const [index, group] of groups.entries()) {
const childName = childNames[index];
const key = item[group];
if(node[key]) {
node = node[key];
} else {
const children = [];
node[entries].push({
[group]: key,
[childName]: children
});
node = node[key] = { [entries]: children };
}
}
node[entries].push(item);
}
const result = tree[entries];
That allows you to access an event as:
for(const event of tree[2017][12][31][entries])
and result
contains the datastructure you needed.
Upvotes: 0