lodash 将对象数组转换为单个键数组和多个值数组

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

我需要传输一些包含太多键值对的数据。 由于密钥相似,我不想将它们与每个对象一起传输。

假设我有以下数据:

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

我需要最终输出为
[ [x,y],[[11,12],[21,22],[31,32],[41,42]] ]
[ [x,y],[11,12],[21,22],[31,32],[41,42] ]

另一端,我应该可以变回原来的样子。 如果它可以处理一些对象中的附加键就太好了

我想我已经看到了一些 close/similar 的 lodash 或下划线函数,但我现在找不到它。

注意:我不知道键是什么

使用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));

更详细一点的方法: [编辑:添加了将其转换回来的功能]

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)

Lodash v4.17.1

修改原文

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();

修改回原来的(按键顺序不是 保证)

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 代码https://jsfiddle.net/wa8kaL5g/1/

在 ES6 中,你可以通过 Object.values(), and Object.keys() 来减少它。您可以使用 Array.prototype.map()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);

使用 Underscore 的解决方案。

先弄清楚按键是什么:

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));

Lodash 的 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>