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,
- get a flat array from the data with a recursion,
- 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 JObject
s
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
Ruby Create Recursive Directory Tree
In Ruby, What Is Stored on the Stack
Heroku App Fails to Start - 'Require': No Such File to Load -- Sinatratestapp (Loaderror)
I'm Getting "Found Character That Cannot Start Any Token While Scanning for the Next Token"
Failing to Install Nokogiri Gem
How to Make Rake Tasks Run Under My Sinantra App/Environment
How to Get a List of All Available Rake Tasks in a Namespace
Pg Error Could Not Connect to Server: Connection Refused Is the Server Running on Port 5432
Why Do I Get "No Implicit Conversion of String into Integer (Typeerror)"
How to Load Some Activerecord Models from a Yaml File and Save Them to the Db
How to Force One Field in Ruby's CSV Output to Be Wrapped with Double-Quotes
Rake Db:Migrate Error with MySQL2 Gem - Library Not Loaded: Libssl.1.0.0.Dylib
Strong Parameters Require Multiple