lodash convert array of objects to single array of keys and multiple array of values

674
December 15, 2016, at 1:05 PM

I need to transmit some data, that has too many key-value pairs. As the keys are similar, I dont want to transmit them with each object.

Consider I have the following data:

[
    {
        x:11,
        y:12
    },{
        x:21,
        y:22
    },{
        x:31,
        y:32
    },{
        x:41,
        y:42
    }
];

And I need the final output as
[ [x,y],[[11,12],[21,22],[31,32],[41,42]] ] OR
[ [x,y],[11,12],[21,22],[31,32],[41,42] ]

On the other end, I should be able to convert back to its original form. It would be great if it can handle an additional key in some of the objects

I think I have seen lodash or underscore function for something close/similar to this, but I'm not able to find it right now.

NOTE: I don't know what the keys will be

Answer 1

Lodash v4.17.1

modify original

var modifiedOriginal = _.chain(original)
    .map(_.keys)
    .flatten()
    .uniq()
    .thru(function(header){
        return _.concat(
            [header],
            _.map(original, function(item) {
                return _.chain(item)
                    .defaults(_.zipObject(
                        header, 
                        _.times(_.size(header), _.constant(undefined))
                     ))
                     .pick(header)
                     .values()
                     .value()
            })
         );  
     })
     .value();

modified back to original (keys order is not guarantee)

var backToOriginal = _.map(_.tail(modified), function(item) { 
     return _.chain(_.head(modified))
         .zipObject(item)
         .transform(function(result, val, key) {
             if (!_.isUndefined(val)) {
                 result[key] = val;
             }
          })
          .value();
 });

JSFiddle code https://jsfiddle.net/wa8kaL5g/1/

Answer 2

Using Array#reduce

var arr = [{ 
  x: 11, 
  y: 12 
}, { 
  x: 21, 
  y: 22 
}, { 
  x: 31, 
  y: 32 
}, { 
  x: 41, 
  y: 42 
}]; 
var keys = Object.keys(arr[0]); 
var op = arr.reduce(function(a, b) { 
  var arr = keys.reduce(function(x, y) { 
    return x.concat([b[y]]); 
  }, []) 
  return a.concat([arr]); 
}, [keys]); //If all the objects are having identical keys! 
console.log(JSON.stringify(op));

Answer 3

A little more verbose way of doing it: [Edit: added the function to convert it back]

function convert(arr) { 
  var retArr = [ [/* keys (retArr[0]) */], [/* values (retArr[1]) */] ] 
  arr.forEach(function(obj){ 
    // create new array for new sets of values 
    retArr[1].push([]) 
 
    // put all of the keys in the correct array 
    for (var key in obj) { 
      if (obj.hasOwnProperty(key)) { 
        // does the key exist in the array yet? 
        if (retArr[0].indexOf(key) === -1) { 
          retArr[0].push(key)   
        } 
 
        // get last index of retArr[1] and push on the values 
        retArr[1][retArr[1].length - 1].push(obj[key]) 
      } 
    } 
  }) 
 
  return retArr 
} 
 
 
function reConvert(arr) { 
  var retArr = [] 
 
  var keys = arr[0] 
 
  arr[1].forEach(function(itemArr){ 
    var obj = {} 
    itemArr.forEach(function(item, i){ 
      obj[keys[i]] = item 
    }) 
    retArr.push(obj) 
  }) 
 
  return retArr 
} 
 
var objArr = [ 
    { 
        x:11, 
        y:12 
    },{ 
        x:21, 
        y:22 
    },{ 
        x:31, 
        y:32 
    },{ 
        x:41, 
        y:42 
    } 
] 
 
var arrFromObj = convert(objArr) 
var objFromArr = reConvert(arrFromObj) 
 
console.log(arrFromObj) 
console.log(objFromArr)

Answer 4

A solution using Underscore.

First work out what the keys are:

var keys = _.chain(data)
    .map(_.keys)
    .flatten()
    .uniq()
    .value();

Then map across the data to pick out the value for each key:

var result = [
    keys, 
    _.map(data, item => _.map(keys, key => item[key]))
];

and back again:

var thereAndBackAgain = _.map(result[1], item => _.omit(_.object(result[0], item), _.isUndefined));

Lodash's version of object is zipObject and omit using a predicate is omitBy:

var thereAndBackAgain = _.map(result[1], item => _.omitBy(_.zipObject(result[0], item), _.isUndefined));

var data = [ 
    { 
        x:11, 
        y:12, 
        aa: 9 
    },{ 
        x:21, 
        y:22 
    },{ 
        x:31, 
        y:32, 
        z: 0 
    },{ 
        x:41, 
        y:42 
    } 
]; 
 
var keys = _.chain(data) 
	.map(_.keys) 
	.flatten() 
	.uniq() 
	.value(); 
 
var result = [ 
	keys,  
	_.map(data, item => _.map(keys, key => item[key])) 
]; 
 
 
var thereAndBackAgain = _.map(result[1], item => _.omit(_.object(result[0], item), _.isUndefined)); 
 
console.log(result) 
console.log(thereAndBackAgain)
<script src=" 
https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>

Answer 5

In ES6 you can do it by reducing it with Object.values(), and Object.keys(). You can restore it using a combination of Array.prototype.map() and Array.prototype.reduce():

const convertStructure = (data) => data.reduce((s, item) => { 
  s[1].push(Object.values(item)); 
  return s; 
}, [Object.keys(data[0]), []]); // all objects should be the same, so we can take the keys from the 1st object 
 
const restoreStructure = ([keys, data]) => data.map((item) => item.reduce((o, v, i) => { 
  o[keys[i]] = v; 
  return o; 
}, {})); 
 
const data = [{ 
  x: 11, 
  y: 12 
}, { 
  x: 21, 
  y: 22 
}, { 
  x: 31, 
  y: 32 
}, { 
  x: 41, 
  y: 42 
}]; 
 
const convertedStructure = convertStructure(data); 
 
console.log('convertedStructure:\n', convertedStructure); 
 
const restoredStructure = restoreStructure(convertedStructure); 
 
console.log('restoredStructure:\n', restoredStructure);

Rent Charter Buses Company
READ ALSO
i want to send a message in hike, is there any api&#39;s provide hike for sending messages?

i want to send a message in hike, is there any api's provide hike for sending messages?

i just want to send messages thorugh apis in hikelet me know is there any API provide hike for sending messages like text,image etc?

255
events.js:160 throw er; // Unhandled &#39;error&#39; event &amp; Error: write after end

events.js:160 throw er; // Unhandled 'error' event & Error: write after end

I am trying to submit a form and displaying data in browser using formidable module of node js but getting following error:

876
Why does my express wildcard route override my static middleware?

Why does my express wildcard route override my static middleware?

I've been having an issue with Express v4

427