Andrew
Andrew

Reputation: 5725

javascript merge array of objects, resulting object values in array

Would like to merge an array of objects resulting in an object of unique keys and array of values (duplication of values is ok). Solutions in vanilla JS or lodash preferred.

eg - from this:

[{ 
  a: 1, 
  b: 2 
}, { 
  a: 1, 
  c: 3 
}]

to this:

{ 
  a: [1, 1],
  b: [2],
  c: [3]
}

Upvotes: 0

Views: 1155

Answers (5)

Ori Drori
Ori Drori

Reputation: 193087

You can use _.mergeWith() with the spread syntax to combine the objects:

const data = [{"a":1,"b":2},{"a":1,"c":3}];

const result = _.mergeWith({}, ...data, (v1 = [], v2) => [...v1, v2]);

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

Upvotes: 3

ryeballar
ryeballar

Reputation: 30118

You can use lodash#mergeWith wrapped in a lodash#spread to make lodash#mergeWith treat an array as a list of arguments. We use lodash#concat as a supporting function to concatenate an empty object (to avoid mutating the objects in the collection), the collection, and the customizer function that merges the entire collection. The customizer is composed using lodash#flow, wherein its first argument is lodash#concat that only accepts an arity of 2 using lodash#ary and the second argument uses lodash#compact -- It removes all undefined values in an array.

var result = _.spread(_.mergeWith)(
  _.concat({}, data, _.flow(_.ary(_.concat, 2), _.compact))
);

var data = [{
  "a": 1,
  "b": 2
}, {
  "a": 1,
  "c": 3
}];

var result = _.spread(_.mergeWith)(
  _.concat({}, data, _.flow(_.ary(_.concat, 2), _.compact))
);

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

Upvotes: 0

Egor Stambakio
Egor Stambakio

Reputation: 18156

ES6 variant:

const a = [{ 
  a: 1, 
  b: 2 
}, { 
  a: 1, 
  c: 3 
}]

const b = a.reduce((acc, cur) => Object.assign(acc, 
  ...Object.keys(cur).map(key => ({ [key]: (acc[key] || []).concat(cur[key]) })))
, {})

console.log(b)

Upvotes: 1

Qiqo
Qiqo

Reputation: 64

A quick search here in stack reveals that @elclanrs already wrote code for that here However based on the comments, it needs a little tweaking to accept an array of objects, so I added a bit of change to the original code itself.

so basically it boils to the function call:

var merge = function() {
  return [].reduce.call(arguments, function(acc, x) {
  for(i=0;i<x.length;i++){
    Object.keys(x[i]).forEach(function(k) {
      acc[k] = (acc[k]||[]).concat([x[i][k]])
    });
    }
    return acc
  },{})
}
}

Here's a snippet using the function call (with a bit of small change I put) in that post:

var x = [{a: 1, b: 2}, {a: 1,c: 3}]

var merge = function() {
  return [].reduce.call(arguments, function(acc, x) {
  for(i=0;i<x.length;i++){
    Object.keys(x[i]).forEach(function(k) {
      acc[k] = (acc[k]||[]).concat([x[i][k]])
    });
    }
    return acc
  },{})
}

y = merge(x);

alert(JSON.stringify(y));

Upvotes: 0

Andrey Ravkov
Andrey Ravkov

Reputation: 1494

without loadash:

  var t = [{ 
  a: 1, 
  b: 2 
}, { 
  a: 1, 
  c: 3 
}];
var result = {};
debugger;
for(var i=0; i<t.length; i++){
    for(var j in t[i]){
        if(result.hasOwnProperty(j)){
            result[j].push(t[i][j]); 
        }else{
            result[j] = [t[i][j]];
        }
    }
}
console.log(result);

Upvotes: 0

Related Questions