javascript - Fastest way to flatten / un-flatten nested JSON objects -


i threw code flatten , un-flatten complex/nested json objects. works, it's bit slow (triggers 'long script' warning).

for flattened names want "." delimiter , [index] arrays.

examples:

un-flattened | flattened --------------------------- {foo:{bar:false}} => {"foo.bar":false} {a:[{b:["c","d"]}]} => {"a[0].b[0]":"c","a[0].b[1]":"d"} [1,[2,[3,4],5],6] => {"[0]":1,"[1].[0]":2,"[1].[1].[0]":3,"[1].[1].[1]":4,"[1].[2]":5,"[2]":6} 

i created benchmark ~simulates use case http://jsfiddle.net/wszec/

  • get nested json object
  • flatten it
  • look through , possibly modify while flattened
  • unflatten it's original nested format shipped away

i faster code: clarification, code completes jsfiddle benchmark (http://jsfiddle.net/wszec/) faster (~20%+ nice) in ie 9+, ff 24+, , chrome 29+.

here's relevant javascript code: current fastest: http://jsfiddle.net/wszec/6/

json.unflatten = function(data) {     "use strict";     if (object(data) !== data || array.isarray(data))         return data;     var result = {}, cur, prop, idx, last, temp;     for(var p in data) {         cur = result, prop = "", last = 0;         {             idx = p.indexof(".", last);             temp = p.substring(last, idx !== -1 ? idx : undefined);             cur = cur[prop] || (cur[prop] = (!isnan(parseint(temp)) ? [] : {}));             prop = temp;             last = idx + 1;         } while(idx >= 0);         cur[prop] = data[p];     }     return result[""]; } json.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 ? prop+"."+i : ""+i);             if (l == 0)                 result[prop] = [];         } else {             var isempty = true;             (var p in cur) {                 isempty = false;                 recurse(cur[p], prop ? prop+"."+p : p);             }             if (isempty)                 result[prop] = {};         }     }     recurse(data, "");     return result; } 

edit 1 modified above @bergi 's implementation fastest. aside, using ".indexof" instead of "regex.exec" around 20% faster in ff 20% slower in chrome; i'll stick regex since it's simpler (here's attempt @ using indexof replace regex http://jsfiddle.net/wszec/2/).

edit 2 building on @bergi 's idea managed created faster non-regex version (3x faster in ff , ~10% faster in chrome). http://jsfiddle.net/wszec/6/ in (the current) implementation rules key names simply, keys cannot start integer or contain period.

example:

  • {"foo":{"bar":[0]}} => {"foo.bar.0":0}

edit 3 adding @aaditmshah 's inline path parsing approach (rather string.split) helped improve unflatten performance. i'm happy overall performance improvement reached.

the latest jsfiddle , jsperf:

http://jsfiddle.net/wszec/14/

http://jsperf.com/flatten-un-flatten/4

here's shorter implementation:

object.unflatten = function(data) {     "use strict";     if (object(data) !== data || array.isarray(data))         return data;     var regex = /\.?([^.\[\]]+)|\[(\d+)\]/g,         resultholder = {};     (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 (and i'm not sure whether need 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 + "[" + + "]");             if (l == 0)                 result[prop] = [];         } else {             var isempty = true;             (var p in cur) {                 isempty = false;                 recurse(cur[p], prop ? prop+"."+p : p);             }             if (isempty && prop)                 result[prop] = {};         }     }     recurse(data, "");     return result; } 

together, run benchmark in half of time (opera 12.16: ~900ms instead of ~ 1900ms, chrome 29: ~800ms instead of ~1600ms).


Comments

Popular posts from this blog

c++ - QTextObjectInterface with Qml TextEdit (QQuickTextEdit) -

javascript - angular ng-required radio button not toggling required off in firefox 33, OK in chrome -

xcode - Swift Playground - Files are not readable -