繁体   English   中英

平坦物体的优雅方式

[英]An elegant way to flatten an object

我面临着使用嵌套的内部扁平化简单对象的繁琐问题。

从SO尝试溶解,但它抛出错误:

const newWeather = Object.assign({}, ...function _flatten(o) { return [].concat(...Object.keys(o).map(k => typeof o[k] === 'object' ? _flatten(o[k]) : ({[k]: o[k]})))}({id: 1}))

// also tried these ones:

    console.log(Object.keys(weatherDetails).reduce((a, b, c) => {
        return Object.assign(a, {
            a: b
        })
    }, {})); 

// another one

let newWeather = Object.assign({}, (function() {
        var obj = {}
        for (var i = 0; i < Object.keys(weatherDetails).length; i++) {
            console.log(i, Object.keys(weatherDetails))
            obj[Object.keys(weatherDetails)] = weatherDetails[Object.keys(weatherDetails)]
        }
        return obj
    })())

这是我需要展平的对象,所以我们需要将其转为:

{ 
    temperature: null, 
    humidity: null, 
    pressure: null, 
    windspeed: null, 
    pollution: {
        PM1: 1,
        PM10: 2,
        PM25: 3
    }
}

进入:

{ 
    temperature: null, 
    humidity: null, 
    pressure: null, 
    windspeed: null, 
    PM1: 1,
    PM10: 2,
    PM25: 3
}

假设您想要一个通用的解决方案,而不是使用静态密钥为您的pollution示例定制的解决方案,这里有一个快速的方法来实现:

您只需遍历对象的属性键即可。 如果属性是对象(让我们称之为子对象),则将子对象的属性复制到主对象。

 const obj = { temperature: null, humidity: null, pressure: null, windspeed: null, pollution: { PM1: 1, PM10: 2, PM25: 3 } }; function flatten(object) { for (const key in object) { if (!object.hasOwnProperty(key)) { continue; } if (typeof object[key] === 'object' && !Array.isArray(object[key]) && object[key] != null) { const childObject = object[key]; delete object[key]; object = {...object, ...childObject}; } } return object; } console.log(flatten(obj)); 

使用Object.entries()方法会更容易

循环遍历对象键和值,删除具有对象作为值的所有条目,并将该值的条目分配给该对象。

 let a = { temperature: null, humidity: null, pressure: null, windspeed: null, pollution: { PM1: 1, PM10: 2, PM25: 3 } } Object.entries(a).map(([key, value]) => { if(value && typeof value === 'object') { delete a[key]; // Delete entry Object.assign(a, value); // Add values from entry to object } }); console.log(a) 

一个班轮:

Object.entries(a).map(([key, value]) => value && typeof value === 'object' && delete a[key] && Object.assign(a, value));

这也是一个不可改变的功能方法:

Object.fromEntries(Object.entries(a).map(([key, value]) => 
    value && typeof value === 'object' ? 
         Object.entries(value) : [[key, value]]
).flat());

我个人更喜欢这种最后一种方法,因为它不会改变原始或任何对象。

只是为了分享一种不同的方法(也许足够优雅),这里是一个依靠函数发生器递归展平对象的解决方案。

因为它依赖于函数生成器,所以最终可以动态构建对象并跳过不需要的键,因为结果是可迭代的。

虽然在原始问题中不需要,但下面的示例有意地使得处理数组和null值稍微复杂一些。

 const original = { temperature: null, humidity: null, pressure: null, windspeed: null, arrayKey: [1,2,3,'star!'], fnKey: function(i) { return i * 3; }, pollution: { PM1: 1, PM10: 2, PM25: 3 } }; // Flattens an object. function* flattenObject(obj, flattenArray = false) { // Loop each key -> value pair entry in the provided object. for (const [key, value] of Object.entries(obj)) { // If the target value is an object and it's not null (because typeof null is 'object'), procede. if (typeof(value) === 'object' && value !== null) { // if the targeted value is an array and arrays should be flattened, flatten the array. if (Array.isArray(value) && flattenArray) yield* flattenObject(value); // Otherwise, if the value is not an array, flatten it (it must be an object-like or object type). else if (!Array.isArray(value)) yield* flattenObject(value); // otherwise, just yield the key->value pair. else yield [key, value]; } // otherwise, the value must be something which is not an object, hence, just yield it. else yield [key, value]; } } // usage: assign to a new object all the flattened properties, using the spread operator (...) to assign the values progressively. const res = Object.fromEntries(flattenObject(original)); console.log(res); // sample usage by flattening arrays as well. const res_flattened_arrays = Object.fromEntries(flattenObject(original, true)); console.log(res_flattened_arrays); // custom object building by skipping a desired key const resWithoutTemperature = {}; for (const [key, value] of flattenObject(original)) { if (key !== 'temperature') resWithoutTemperature[key] = value; } console.log(resWithoutTemperature); 

只需合并并删除作为Objectof instanceof的每个子属性。

 let obj = { temperature: null, humidity: null, pressure: null, windspeed: null, pollution: { PM1: 1, PM10: 2, PM25: 3, pollution: 4 } }; function flatten(obj) { obj = Object.assign({}, obj); for (let i in obj) if (obj[i] instanceof Object) { obj = Object.assign(obj, obj[i]); // Prevent deletion of property i/"pollution", if it was not replaced by one of the child object's properties if (obj[i] === obj[i][i]) delete obj[i]; } return obj; } let obj_flattened = flatten(obj); console.log(obj_flattened); 

我通常使用Lodash进行这些转换。 有了它,这样做非常简单。

查看以下代码示例:

const data = { 
    temperature: null, 
    humidity: null, 
    pressure: null, 
    windspeed: null, 
    pollution: {
        PM1: 1,
        PM10: 2,
        PM25: 3
    }
};

let flat = _.merge(data, data.pollution);
delete flat.pollution;
console.log(flat); // returns {"temperature":null,"humidity":null,"pressure":null,"windspeed":null,"PM1":1,"PM10":2,"PM25":3}

试试这个(它将展平任何对象中包含的任何对象)迭代对象属性并识别属性是否是另一个要平坦的对象并添加到“root”对象:

var o = { 
    temperature: null, 
    humidity: null, 
    pressure: null, 
    windspeed: null, 
    pollution: {
        PM1: 1,
        PM10: 2,
        PM25: 3,
        newobject:{
            a:1,
            b:2,
            c: {
                x:3,
                y:4,
                z:5                 
            }
        }
    }
}

    function flatten(obj){
        let retObj = {};
        let objConst = {}.constructor;
        for (el in obj){
            if(obj[el] !== null && obj[el].constructor === objConst){
                retObj = Object.assign({}, retObj, flatten(obj[el]));
            } else {
                retObj[el] = obj[el];
            }
        }
        return retObj;
    }

    console.log(flatten(o));

暂无
暂无

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

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