al3x1s
al3x1s

Reputation: 70

Reorder array object with lodash

I want to reorder this array:

[{ a: "v1", b: "v2"} , {a: "v3", b: "v4"}]

to this:

{a: ["v1", "v3"] , b: ["v2", "v4"]}

Note: It is necessary to guarantee order, the first array element should be the first element in the array value in each key object

Upvotes: 0

Views: 1489

Answers (5)

Maurits Rijk
Maurits Rijk

Reputation: 9985

Another (short) lodash solution, using a combination of reduce and mergeWith:

_.reduce(data, (acc, x) => _.mergeWith(acc, x, 
                                            (obj = [], src) => obj.concat(src)),
         {});

Or a bit more readable:

const customizer = (obj = [], src) => obj.concat(src);
_.reduce(data, (acc, x) => _.mergeWith(acc, x, customizer), {});

Or even:

const customizer = (obj = [], src) => obj.concat(src);
_.reduce(data, _.partialRight(_.mergeWith, customizer), {});

Upvotes: 0

ryeballar
ryeballar

Reputation: 30098

Here's a lodash solution that uses the combination of spread and mergeWith to merge all the objects with similar properties.

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

var data = [{
  a: "v1",
  b: "v2"
}, {
  a: "v3",
  b: "v4"
}, {
  a: "v5",
  b: "v6",
  c: "1"
}];

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

console.log(result);
body>div {
  min-height: 100%;
  top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

Upvotes: 0

RomanPerekhrest
RomanPerekhrest

Reputation: 92854

Alternative solution using Array.prototype.reduce() and Object.keys() function:

var arr = [{ a: "v1", b: "v2"} , {a: "v3", b: "v4"}],
    result = arr.reduce(function (r, o) {
        Object.keys(o).forEach(function(k){ (r[k])? r[k].push(o[k]) : r[k] = [o[k]]; });
        return r;
    }, {});

console.log(result);

Upvotes: 0

Thomas
Thomas

Reputation: 12637

An extended Version of @Kind user's code, that also deals with objects that have different keys:

function mapByKey(source){
  var result = Object.create(null);
  source.forEach((item, index) => {
    if(item == null) return;
    Object.keys(item).forEach(key => {
      if(!(key in result)){
        //don't use sparse Arrays
        result[key] = Array(source.length).fill(undefined); 
      }

      result[key][index] = item[key];
    })
  })
  return result;
}

var array = [
  {a: "v1", b: "v2"}, 
  {a: "v3", c: "v4"}, 
  {b: "v5", c: "v7"}
];
var mapping = mapByKey(array);

console.log(mapping);

//or something funny:
console.log(mapByKey(["foo", "bar", "baz", "asdf"]));

The point of this version, is that even if your Array contains Objects with different keys (like in the example, one object has a and b, one has a and c and one has b and c), this will always be true:

array[index][key] === mapping[key][index];

Upvotes: 0

kind user
kind user

Reputation: 41893

Pure js solution, using Array#forEach and Object.keys.

var arr = [{ a: "v1", b: "v2"} , {a: "v3", b: "v4"}],
    obj = {};
    
    arr.forEach(c => Object.keys(c).forEach(function(v){
      (obj[v] || (obj[v] = [])).push(c[v]);
    }));
    
    console.log(obj);
        

Upvotes: 1

Related Questions