简体   繁体   English

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

[英]lodash convert array of objects to single array of keys and multiple array of values

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]] ]
[ [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. 我想我已经看到lodash或下划线功能与之接近/相似,但是我现在无法找到它。

NOTE: I don't know what the keys will be 注意:我不知道键是什么

Using Array#reduce 使用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)); 

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) 

A solution using Underscore. 使用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 : Lodash的版本的对象zipObject省略使用谓词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> 

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

In ES6 you can do it by reducing it with Object.values() , and Object.keys() . 在ES6中,可以通过使用Object.values()Object.keys()减少它来Object.values() You can restore it using a combination of Array.prototype.map() and Array.prototype.reduce() : 您可以结合使用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); 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM