Reputation: 357
I am facing trival problem to flatten simple object with nested one inside.
Tried sollution fro SO, but it throws error:
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
})())
Here is my object I need to flatten, so we need to turn this:
{
temperature: null,
humidity: null,
pressure: null,
windspeed: null,
pollution: {
PM1: 1,
PM10: 2,
PM25: 3
}
}
Into this:
{
temperature: null,
humidity: null,
pressure: null,
windspeed: null,
PM1: 1,
PM10: 2,
PM25: 3
}
Upvotes: 1
Views: 914
Reputation: 483
Post ES6, you can use the below as an elegant and clean solution:
const data = {
temperature: null,
humidity: null,
pressure: null,
windspeed: null,
pollution: {
PM1: 1,
PM10: 2,
PM25: 3
}
};
const { pollution, ...rest} = data;
const flattenedData = {...rest, ...pollution};
console.log(flattenedData)
Upvotes: 0
Reputation: 134
Just merge and delete every child property that's an instanceof Object.
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);
Upvotes: 0
Reputation: 4819
This would be easier with the Object.entries() method
You loop over the object keys and values, delete all entries that have an object as value and assign the entries off that value to the object.
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)
One liner:
Object.entries(a).map(([key, value]) => value && typeof value === 'object' && delete a[key] && Object.assign(a, value));
Also here's a immutable functional approach:
Object.fromEntries(Object.entries(a).map(([key, value]) =>
value && typeof value === 'object' ?
Object.entries(value) : [[key, value]]
).flat());
Personally I prefer this last approach since it doesn't mutate the original or any object.
Upvotes: 1
Reputation: 807
Try this (it will flatten any object contained in any object) iterating through the object attributes and identifying if an attribute is another object to flat and add to the "root" one:
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));
Upvotes: 0
Reputation: 7446
Just to share a different approach (elegant enough, maybe), here is a solution relying on function generators to recursively flatten an object.
Because it relies on function generators, you can eventually build the object dynamically and skip undesired keys due to the fact the the result is iterable.
The below example has intentionally been made slightly more complex to handle arrays and null
values as well, though not required in the original question.
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);
Upvotes: 1
Reputation: 5825
Assuming you want to have a generic solution, not one that's custom-tailored to your pollution
example with static keys, here's a quick way of achieving that:
You just iterate through your object's property keys. If a property is an object (let's call it child object), you'll copy your child object's properties to your main object.
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));
Upvotes: 1
Reputation: 911
I usually use Lodash for these kinds of transformations. With it, it's very straightforward to do so.
Check out the following code sample:
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}
Upvotes: 0