jgr0
jgr0

Reputation: 727

lodash: combine array of objects

In lodash, I want to convert an array of objects to a single object that contains an array of each property.

I have an array of objects:

var students = [{
    name: 'A',
    idNo: 1,
    marks: {
        math: 98,
        sci: 97,
        eng: 89
    }
}, {
    name: 'B',
    idNo: 2,
    marks: {
        math: 88,
        sci: 87,
        eng: 79
    }
}, {
    name: 'C',
    idNo: 3,
    marks: {
        math: 87,
        sci: 98,
        eng: 91
    }
}]

I want to combine / reshape them like this:

{
    name: [A, B, C],
    idNo: [1, 2, 3],
    marks: [{
            math: 98,
            sci: 97,
            eng: 89
        }, {

            math: 88,
            sci: 87,
            eng: 79            
    }, {
            math: 87,
            sci: 98,
            eng: 91
        }
    }]
}

I want this to be done purely with lodash or js inbuilt functions without any loops.

Edit : I have already implemented a solution as suggested by Nenad. I want a utility function in lodash.

Upvotes: 6

Views: 13372

Answers (6)

Ori Drori
Ori Drori

Reputation: 191976

You can merge all objects in the array to a new object using _.mergeWith() with the spread operator:

const students = [{"name":"A","idNo":1,"marks":{"math":98,"sci":97,"eng":89}},{"name":"B","idNo":2,"marks":{"math":88,"sci":87,"eng":79}},{"name":"C","idNo":3,"marks":{"math":87,"sci":98,"eng":91}}];

const result = _.mergeWith({}, ...students, (objValue, srcValue) => 
  (objValue || []).concat(srcValue));

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.4/lodash.min.js"></script>

In older browser's you can concat all parameters to a single array, and use _.spread():

var students = [{"name":"A","idNo":1,"marks":{"math":98,"sci":97,"eng":89}},{"name":"B","idNo":2,"marks":{"math":88,"sci":87,"eng":79}},{"name":"C","idNo":3,"marks":{"math":87,"sci":98,"eng":91}}];
                                          
var result = _.spread(_.mergeWith)([{}].concat(students, function(objValue, srcValue){
  return (objValue || []).concat(srcValue);
}));

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.4/lodash.min.js"></script>

Upvotes: 1

Gruff Bunny
Gruff Bunny

Reputation: 27976

You could use lodash's mapValues function:

var result = _.mapValues(students[0], (value, key) => _.map(students, key));

mapValues creates an object with the same keys as the object passed to it as the first parameter. Here we pass the first object in the students array students[0] so the object returned by mapValues will look something like this:

{
    name: ....,
    idNo: ....,
    marks: ....
}

The value for each key is determined by the function that is passed to mapValues as the second parameter. mapValues will call this function for each key and pass the value and the key. We're not interested in the value but the key is used to pluck all the values in the student array for that key (by calling map with the key as the second parameter).

var students = [{
    name: 'A',
    idNo: 1,
    marks: {
        math: 98,
        sci: 97,
        eng: 89
    }
}, {
    name: 'B',
    idNo: 2,
    marks: {
        math: 88,
        sci: 87,
        eng: 79
    }
}, {
    name: 'C',
    idNo: 3,
    marks: {
        math: 87,
        sci: 98,
        eng: 91
    }
}]


var result = _.mapValues(students[0], (value, key) => _.map(students, key));

document.getElementById('result').textContent = JSON.stringify(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

<p>
  <pre id="result"></pre>
</p>

Upvotes: 7

Yosvel Quintero
Yosvel Quintero

Reputation: 19070

Another lodash example with .reduce(collection, [iteratee=.identity], [accumulator]).

  • collection (Array|Object): The collection to iterate over.
  • [iteratee=_.identity] (Function): The function invoked per iteration.
  • [accumulator] (*): The initial value.

Code:

var students = [{name: 'A', idNo: 1, marks: { math: 98, sci: 97, eng: 89}}, {name: 'B', idNo: 2, marks: { math:88,  sci: 87,  eng: 79}}, {name: 'C', idNo: 3, marks: { math: 87, sci: 98, eng: 91}}],
    obj = _.reduce(students, function(o, item) {
      o.name.push(item.name);
      o.idNo.push(item.idNo);
      o.marks.push(item.marks);
      return o;
    }, {name: [], idNo: [], marks: []});

console.log(obj);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

Upvotes: 0

Nina Scholz
Nina Scholz

Reputation: 386560

Just another lodash example with _.mergeWith

var students = [{ name: 'A', idNo: 1, marks: { math: 98, sci: 97, eng: 89 } }, { name: 'B', idNo: 2, marks: { math: 88, sci: 87, eng: 79 } }, { name: 'C', idNo: 3, marks: { math: 87, sci: 98, eng: 91 } }],
    result = {};

    _.forEach(students, v => _.mergeWith(result, v, (o, s) => !_.isArray(o) ? [s] : o.concat(s)));

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

Upvotes: 0

Redu
Redu

Reputation: 26161

You might do it with a single reduce;

var students = [{
    name: 'A',
    idNo: 1,
    marks: {
        math: 98,
        sci: 97,
        eng: 89
    }
}, {
    name: 'B',
    idNo: 2,
    marks: {
        math: 88,
        sci: 87,
        eng: 79
    }
}, {
    name: 'C',
    idNo: 3,
    marks: {
        math: 87,
        sci: 98,
        eng: 91
    }
}],
     result = students.reduce((p,c) => (p.name.push(c.name), p.idNo.push(c.idNo), p.marks.push(c.marks), p), {name:[], idNo:[], marks:[]});
console.log(result);

Upvotes: 0

Nenad Vracar
Nenad Vracar

Reputation: 122037

You can use reduce() and forEach() to get desired result.

var students = [{"name":"A","idNo":1,"marks":{"math":98,"sci":97,"eng":89}},{"name":"B","idNo":2,"marks":{"math":88,"sci":87,"eng":79}},{"name":"C","idNo":3,"marks":{"math":87,"sci":98,"eng":91}}];

var result = students.reduce(function(r, e) {
  Object.keys(e).forEach(function(k) {
    if (!r[k]) {
      r[k] = [];
    }
    r[k].push(e[k])
  })
  return r;
}, {})

console.log(result)

Upvotes: 0

Related Questions