3
\$\begingroup\$

I have an array like this:

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.

\$\endgroup\$
7
  • \$\begingroup\$ Try it out here glot.io/snippets/ee5bgy3ejx \$\endgroup\$ Commented Apr 27, 2016 at 12:38
  • \$\begingroup\$ What happens to text when merging? \$\endgroup\$
    – Joseph
    Commented Apr 27, 2016 at 12:56
  • \$\begingroup\$ The text values are the same if they got the same revision value \$\endgroup\$ Commented Apr 27, 2016 at 12:58
  • \$\begingroup\$ That may need to be mentioned in the post. \$\endgroup\$
    – Joseph
    Commented Apr 27, 2016 at 12:59
  • \$\begingroup\$ You're right, I add that \$\endgroup\$ Commented Apr 27, 2016 at 13:00

1 Answer 1

3
\$\begingroup\$

This can be done natively:

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.

\$\endgroup\$
1
  • \$\begingroup\$ I forgot to mention I am not using ES6 (added to the question by now) but it's probably easily portable. Your code is really pretty though. \$\endgroup\$ Commented Apr 27, 2016 at 14:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.