patternjavascriptMinor
Concat a collection's sub arrays and merge their parent
Viewed 0 times
arraysmergesubcollectionparentandconcattheir
Problem
I have an array like this:
And I'd like to concat its details arrays if the revision is the same (the
Here is what I came up with:
But I'm not 100% satisfied with it. What could be improved?
I'm not using ES6.
var arr = [
{
revision: 19,
text: 'hello',
details: [
{
id: 5
}
]
},
{
revision: 19,
text: 'hello',
details: [
{
id: 6
}
]
},
{
revision: 17,
text: 'world',
details: [
{
id: 7
}
]
}
];And I'd like to concat its details arrays if the revision is the same (the
text values are the same if they got the same revision value):var expected = [
{
revision: 19,
text: 'hello',
details: [
{
id: 5
},
{
id: 6
}
]
},
{
revision: 17,
text: 'world',
details: [
{
id: 7
}
]
}
];Here is what I came up with:
constructArray(groupByRevisionNb(arr));
function groupByRevisionNb(arr) {
return _.groupBy(arr, 'revision');
}
function constructArray(obj) {
return _.map(obj, function (arr) {
return concatRevisions(arr);
});
}
function concatRevisions(arr) {
return _.reduce(arr, function (obj1, obj2) {
if (_.isEmpty(obj1)) {
obj1 = _.clone(obj2);
} else {
obj1.details = obj1.details.concat(obj2.details);
}
return obj1;
}, {});
}But I'm not 100% satisfied with it. What could be improved?
I'm not using ES6.
Solution
This can be done natively:
First, make a mapping of ID to revision data. This way, we can easily check the existence of an already visited revision and know when to append rather than assign. Then, we convert that object into an array.
The only thing not native is the use of
var revisionMap = arr.reduce((map, entry) => {
var revision = entry.revision;
if(map.hasOwnProperty(revision))
map[revision].details.push(...entry.details);
else
map[revision] = _.clone(entry);
return map;
}, {});
/*
{
1: { revision: REV, text: TEXT, details: [] },
2: { revision: REV, text: TEXT, details: [] },
}
*/
var expected = Object.keys(revisionMap).map( key => revisionMap[key] );
/*
[
{ revision: REV, text: TEXT, details: [] },
{ revision: REV, text: TEXT, details: [] },
]
*/First, make a mapping of ID to revision data. This way, we can easily check the existence of an already visited revision and know when to append rather than assign. Then, we convert that object into an array.
The only thing not native is the use of
_.clone as we don't want to be modifying the original data when we're be appending details.Code Snippets
var revisionMap = arr.reduce((map, entry) => {
var revision = entry.revision;
if(map.hasOwnProperty(revision))
map[revision].details.push(...entry.details);
else
map[revision] = _.clone(entry);
return map;
}, {});
/*
{
1: { revision: REV, text: TEXT, details: [] },
2: { revision: REV, text: TEXT, details: [] },
}
*/
var expected = Object.keys(revisionMap).map( key => revisionMap[key] );
/*
[
{ revision: REV, text: TEXT, details: [] },
{ revision: REV, text: TEXT, details: [] },
]
*/Context
StackExchange Code Review Q#126837, answer score: 3
Revisions (0)
No revisions yet.