Flatten a Nested JSON Object

Fastest way to flatten / un-flatten nested JavaScript objects

Here's my much shorter implementation:

Object.unflatten = function(data) {
"use strict";
if (Object(data) !== data || Array.isArray(data))
return data;
var regex = /\.?([^.\[\]]+)|\[(\d+)\]/g,
resultholder = {};
for (var p in data) {
var cur = resultholder,
prop = "",
m;
while (m = regex.exec(p)) {
cur = cur[prop] || (cur[prop] = (m[2] ? [] : {}));
prop = m[2] || m[1];
}
cur[prop] = data[p];
}
return resultholder[""] || resultholder;
};

flatten hasn't changed much (and I'm not sure whether you really need those isEmpty cases):

Object.flatten = function(data) {
var result = {};
function recurse (cur, prop) {
if (Object(cur) !== cur) {
result[prop] = cur;
} else if (Array.isArray(cur)) {
for(var i=0, l=cur.length; i<l; i++)
recurse(cur[i], prop + "[" + i + "]");
if (l == 0)
result[prop] = [];
} else {
var isEmpty = true;
for (var p in cur) {
isEmpty = false;
recurse(cur[p], prop ? prop+"."+p : p);
}
if (isEmpty && prop)
result[prop] = {};
}
}
recurse(data, "");
return result;
}

Together, they run your benchmark in about the half of the time (Opera 12.16: ~900ms instead of ~ 1900ms, Chrome 29: ~800ms instead of ~1600ms).

Note: This and most other solutions answered here focus on speed and are susceptible to prototype pollution and shold not be used on untrusted objects.

How to flatten multilevel/nested JSON?

I used the following function (details can be found here):

def flatten_data(y):
out = {}

def flatten(x, name=''):
if type(x) is dict:
for a in x:
flatten(x[a], name + a + '_')
elif type(x) is list:
i = 0
for a in x:
flatten(a, name + str(i) + '_')
i += 1
else:
out[name[:-1]] = x

flatten(y)
return out

This unfortunately completely flattens whole JSON, meaning that if you have multi-level JSON (many nested dictionaries), it might flatten everything into single line with tons of columns.

What I used, in the end, was json_normalize() and specified structure that I required. A nice example of how to do it that way can be found here.

Flatten nested JSON object

If you want JSON output:

const people = {
name: 'My Name',
cities: [{city: 'London', country: 'UK'},{city: 'Mumbai', country: 'IN'},{city: 'New York', country: 'US'}],
}

let result = people.cities.map(data => {
return {
name: people.name,
city: data.city,
country: data.country
}
})

console.log(result)

Flatten and sort a nested JSON object into an array in javascript

You could split the task into two parts,

  1. get a flat array from the data with a recursion,
  2. sort by wanted keys descending.

const
flat = (object, [key, ...keys], values = {}) => Object
.entries(object)
.flatMap(([k, v]) => {
const right = { ...values, [key]: k };
return Array.isArray(v)
? v.map(o => ({ ...right, ...o }))
: flat(v, keys, right);
}),
keys = ['year', 'month', 'day'],
data = { 2021: { '08': { 26: [{ name: 'Bob', age: 34 }, { name: 'Alice', age: 33 }], 27: [{ name: 'Jane', age: 21 }] }, '09': { '03': [{ name: 'John', age: 47 }, { name: 'Sue', age: 36 }] } }, 2022: { '04': { '05': [{ name: 'David', age: 26 }] } } },
result = flat(data, keys)
.sort((a, b) => {
let r;
keys.some(k => r = b[k] - a[k]);
return r;
});

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

How to flatten a column of nested json objects in an already flattened dataframe

You can apply some post-processing to df0 to achieve what you want. Here you can apply explode followed by apply(pf.Series) applied to 'marketStats' column:

df1 = df0.explode('marketStats')['marketStats'].apply(pd.Series)

df1 looks like this:

    algorithm       ratio    medianDrop    medianBounce    hoursToRespected    crackedCount    respectedCount
-- ------------ ------- ------------ -------------- ------------------ -------------- ----------------
0 original 50 -4.08 5.51 106 2 1
0 day_trade 100 -6.12 6.28 204 1 1
0 conservative 100 -6.12 8.38 204 1 1
0 position 50 -6.12 6.19 204 2 1
0 hodloo 50 -3.29 0 225 4 2
1 original 57.14 -3.28 3.84 186 7 4
1 day_trade 0 0 5.68 0 1 0
1 conservative 0 0 5.68 0 1 0
1 position 0 0 8.16 0 1 0
1 hodloo 75 -3.7 0 35 4 3
2 original 100 -7.18 4.34 62 2 2
2 day_trade 100 -6.19 4.3 63 1 1
2 conservative 66.67 -3.15 4.05 62 3 2
2 position 100 -3.15 4.46 60 2 2
2 hodloo 100 -7.46 0 62 5 5

if you want it combined with all the other columns you can use join:

df0.join(df1)

I am not going to post the output of this command as it is rather large

Javascript - How to Flatten a nested JSON object

function flatten(json) {
var newJSON = [];
for (var i = 0; i < json.length; i++) {
var obj = {};
for (var key in json[i]) {
if (json[i].hasOwnProperty(key)) {
obj['dv_' + key] = json[i][key]['display_value'];
obj[key] = json[i][key]['value'];
}
}
newJSON.push(obj);
}
return newJSON;
}

var jsonUnflattenInput = [

{
"u_summary": {
"display_value": "Please check the data and set the company accordingly if everything is fine.",
"value": "Please check the data."
},
"created_date": {
"display_value": "2022-06-18 11:45:00",
"value": "2022-05-29 21:42:01"
},
"u_product": {
"display_value": "Undefined",
"value": "2345567"
}
},
{
"u_summary": {
"display_value": "╓ tool v14.3",
"value": "14.3"
},
"created_date": {
"display_value": "2022-03-18 11:45:00",
"value": "2022-02-29 21:42:01"
},
"u_product": {
"display_value": "test_product",
"value": "1367"
}
}
]

console.log(flatten(jsonUnflattenInput))

C# - Flatten Nested Json

To create a datatable from your source json you will need this code:

JObject jsonObject = JObject.Parse(json);
List<string> jpaths = jsonObject.Descendants().OfType<JProperty>().Where(jp => jp.Value is JArray).Select(jp => jp.Path).ToList();
List<JToken> rowtokens = jsonObject.SelectTokens("$.d.results.[*]").ToList();

DataTable resultTable = new DataTable();
resultTable.Columns.AddRange(((JObject)rowtokens[0]).Descendants().OfType<JProperty>().Where(jp => jp.Value is JValue).Select(jp => new DataColumn(jp.Path)).ToArray());
foreach (JToken rowtoken in rowtokens)
{
resultTable.Rows.Add(((JObject)rowtoken).Descendants().OfType<JProperty>().Where(jp => jp.Value is JValue).Select(jp => jp.Value.ToString()).ToArray());
}

Flatten nested JSON with JSON.NET in C#

First let's define a mapper

JObject Map(JObject source)
{
var result = (JObject)source.DeepClone();
result.Remove("Children");
return result;
}
  • It simply clones the object and removes the Children property

Next let's define a recursive function to accumulate the JObjects

void Flatten(JArray children, JArray accumulator)
{
if (children == null) return;
foreach (JObject child in children)
{
accumulator.Add(Map(child));
Flatten((JArray)child["Children"], accumulator);
}
}

And finally let's make use of them

var semiParsed = JObject.Parse(json);

var accumulator = new JArray();
accumulator.Add(Map(semiParsed));
Flatten((JArray)semiParsed["Children"], accumulator);

The ToString call on the accumulator will return this

[
{
"Quantity": 0,
"QuantityUnit": "pcs",
"PartNumber": "12345",
"Parent": ""
},
{
"Quantity": 1,
"QuantityUnit": "pcs",
"PartNumber": "88774",
"Parent": "12345"
},
{
"Quantity": 1,
"QuantityUnit": "pcs",
"PartNumber": "42447",
"Parent": "88774"
},
{
"Quantity": 0.42,
"QuantityUnit": "kg",
"PartNumber": "12387",
"Parent": "88774"
}
]

UPDATE #1

If your source json contains a deep hierarchy (lets say more than 5 levels) then the DeepClone is not really efficient, since you are copying the whole subtree.

To fix this problem you just need to rewrite the Map function

JObject Map(JObject source)
=> JObject.FromObject(new
{
Quantity = (double)source["Quantity"],
QuantityUnit = (string)source["QuantityUnit"],
PartNumber = (string)source["PartNumber"],
Parent = (string)source["Parent"]
});


Related Topics



Leave a reply



Submit