Ich habe Code zusammengeschmissen, um komplexe / verschachtelte JSON-Objekte zu reduzieren und zu entfernen. Es funktioniert, ist aber etwas langsam (löst die Warnung "Langes Skript" aus).
Für die abgeflachten Namen möchte ich "." als Trennzeichen und [INDEX] für Arrays.
Beispiele:
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}
Ich habe einen Benchmark erstellt, der meinen Anwendungsfall simuliert. Http://jsfiddle.net/WSzec/
- Ruft ein verschachteltes JSON-Objekt ab
- Flache es ab
- Schauen Sie es durch und ändern Sie es möglicherweise, während es abgeflacht ist
- Entflachen Sie es wieder auf das ursprüngliche verschachtelte Format, um es zu versenden
Ich möchte schnelleren Code: Zur Verdeutlichung Code, der den JSFiddle-Benchmark ( http://jsfiddle.net/WSzec/ ) in IE 9+, FF 24+ und Chrome 29 deutlich schneller (~ 20% + wäre schön) vervollständigt +.
Hier ist der relevante JavaScript-Code: Aktuell am schnellsten: 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;
do {
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;
for (var p in cur) {
isEmpty = false;
recurse(cur[p], prop ? prop+"."+p : p);
}
if (isEmpty)
result[prop] = {};
}
}
recurse(data, "");
return result;
}
BEARBEITEN 1 Das oben Gesagte wurde an die Implementierung von @Bergi geändert, die derzeit die schnellste ist. Abgesehen davon ist die Verwendung von ".indexOf" anstelle von "regex.exec" in FF etwa 20% schneller, in Chrome jedoch 20% langsamer. Also bleibe ich bei der Regex, da es einfacher ist (hier ist mein Versuch, indexOf zu verwenden, um die Regex zu ersetzen http://jsfiddle.net/WSzec/2/ ).
EDIT 2 Aufbauend auf der Idee von @Bergi habe ich es geschafft, eine schnellere Nicht-Regex-Version zu erstellen (3x schneller in FF und ~ 10% schneller in Chrome). http://jsfiddle.net/WSzec/6/ In dieser (aktuellen) Implementierung lauten die Regeln für Schlüsselnamen einfach: Schlüssel dürfen nicht mit einer Ganzzahl beginnen oder einen Punkt enthalten.
Beispiel:
- {"foo": {"bar": [0]}} => {"foo.bar.0": 0}
BEARBEITEN 3BEARBEITEN Durch Hinzufügen des Inline-Pfad-Parsing-Ansatzes von @AaditMShah (anstelle von String.split) konnte die Leistung beim Abflachen verbessert werden. Ich bin sehr zufrieden mit der insgesamt erzielten Leistungsverbesserung.
Die neuesten jsfiddle und jsperf:
quelle
[1].[1].[0]
sieht für mich falsch aus. Sind Sie sicher, dass dies das gewünschte Ergebnis ist?Antworten:
Hier ist meine viel kürzere Implementierung:
flatten
hat sich nicht viel geändert (und ich bin mir nicht sicher, ob Sie dieseisEmpty
Fälle wirklich brauchen ):Zusammen führen sie Ihren Benchmark in etwa der Hälfte der Zeit aus (Opera 12.16: ~ 900 ms statt ~ 1900 ms, Chrome 29: ~ 800 ms anstelle von ~ 1600 ms).
Hinweis: Diese und die meisten anderen hier beantworteten Lösungen konzentrieren sich auf die Geschwindigkeit und sind anfällig für Prototypenverschmutzung. Sie dürfen nicht für nicht vertrauenswürdige Objekte verwendet werden.
quelle
result === data
wird nicht funktionieren, sie sind nie identisch.Ich habe zwei Funktionen
flatten
undunflatten
ein JSON-Objekt geschrieben.Reduzieren Sie ein JSON-Objekt :
Leistung :
Entflachen Sie ein JSON-Objekt :
Leistung :
Reduzieren und reduzieren Sie ein JSON-Objekt :
Insgesamt ist meine Lösung entweder gleich gut oder sogar besser als die aktuelle Lösung.
Leistung :
Ausgabeformat :
Ein abgeflachtes Objekt verwendet die Punktnotation für Objekteigenschaften und die Klammernotation für Arrayindizes:
{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}
Meiner Meinung nach ist dieses Format besser als nur die Punktnotation:
{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}
Vorteile :
Nachteile :
Die aktuelle JSFiddle-Demo lieferte die folgenden Werte als Ausgabe:
Meine aktualisierte JSFiddle-Demo ergab die folgenden Werte als Ausgabe:
Ich bin mir nicht sicher, was das bedeutet, also bleibe ich bei den jsPerf-Ergebnissen. Immerhin ist jsPerf ein Dienstprogramm zum Leistungsbenchmarking. JSFiddle ist nicht.
quelle
unflatten({"foo.__proto__.bar": 42})
3 ½ Jahre später ...
Für mein eigenes Projekt wollte ich JSON-Objekte in MongoDB-Punktnotation reduzieren und fand eine einfache Lösung:
Merkmale und / oder Einschränkungen
{a: () => {}}
Sie möglicherweise nicht das, was Sie wollten!{a: {}, b: []}
ist also abgeflacht{}
.quelle
{"x": "abc\"{x}\"yz"}
wird{ "x": "abc"{,"x",}"yz"}
was ungültig ist.ES6-Version:
Beispiel:
quelle
Date
, eine Idee, wie man es dazu bringt ? Zum Beispiel mitflatten({a: {b: new Date()}});
Hier ist ein anderer Ansatz, der langsamer läuft (ungefähr 1000 ms) als die obige Antwort, aber eine interessante Idee hat :-)
Anstatt jede Eigenschaftskette zu durchlaufen, wird nur die letzte Eigenschaft ausgewählt und für den Rest eine Nachschlagetabelle verwendet, um die Zwischenergebnisse zu speichern. Diese Nachschlagetabelle wird wiederholt, bis keine Eigenschaftsketten mehr vorhanden sind und sich alle Werte auf nicht verketteten Eigenschaften befinden.
Es verwendet derzeit die
data
Eingabeparameter für die Tabelle verwendet und es werden viele Eigenschaften hinzugefügt. Eine zerstörungsfreie Version sollte ebenfalls möglich sein. Vielleicht ist eine cleverelastIndexOf
Verwendung besser als die Regex (hängt von der Regex-Engine ab).Sehen Sie es hier in Aktion .
quelle
unflatten
das abgeflachte Objekt nicht korrekt wiedergibt. Betrachten Sie zum Beispiel das Array[1,[2,[3,4],5],6]
. Ihreflatten
Funktion glättet dieses Objekt auf{"[0]":1,"[1][0]":2,"[1][1][0]":3,"[1][1][1]":4,"[1][2]":5,"[2]":6}
. Ihreunflatten
Funktion hebt das abgeflachte Objekt jedoch fälschlicherweise auf[1,[null,[3,4]],6]
. Der Grund dafür ist die Anweisung,delete data[p]
die den Zwischenwert vorzeitig löscht,[2,null,5]
bevor er[3,4]
hinzugefügt wird. Verwenden Sie einen Stapel, um es zu lösen. :-)Sie können https://github.com/hughsk/flat verwenden
Beispiel aus dem Dokument
quelle
Dieser Code glättet rekursiv JSON-Objekte.
Ich habe meinen Zeitmechanismus in den Code aufgenommen und er gibt mir 1 ms, aber ich bin mir nicht sicher, ob das der genaueste ist.
Ausgabe:
quelle
typeof some === 'object'
ist schneller alssome instanceof Object
da die erste Prüfung in O1 ausgeführt wird, während die zweite in On ausgeführt wird, wobei n eine Länge einer Vererbungskette ist (Objekt wird dort immer das letzte sein).Ich habe der ausgewählten Antwort eine Effizienz von +/- 10-15% hinzugefügt, indem ich den Code umgestaltet und die rekursive Funktion außerhalb des Funktionsnamensraums verschoben habe.
Siehe meine Frage: Werden Namespace-Funktionen bei jedem Aufruf neu bewertet? warum dies verschachtelte Funktionen verlangsamt.
Siehe Benchmark .
quelle
Hier ist meins. Es wird in <2 ms in Google Apps Script auf einem großen Objekt ausgeführt. Es werden Bindestriche anstelle von Punkten für Trennzeichen verwendet, und es werden keine Arrays speziell wie in der Frage des Fragestellers behandelt, aber dies ist das, was ich für meine Verwendung wollte.
Beispiel:
Beispielausgabe:
quelle
Verwenden Sie diese Bibliothek:
Verwendung (von https://www.npmjs.com/package/flat ):
Ebnen:
Abflachen:
quelle
Ich möchte eine neue Version von Flatten Case hinzufügen (das ist, was ich brauchte :)), die laut meinen Tests mit dem obigen jsFiddler etwas schneller ist als die aktuell ausgewählte. Außerdem sehe ich persönlich diesen Ausschnitt etwas lesbarer, was natürlich für Projekte mit mehreren Entwicklern wichtig ist.
quelle
Hier ist ein Code, den ich geschrieben habe, um ein Objekt zu reduzieren, mit dem ich gearbeitet habe. Es wird eine neue Klasse erstellt, die jedes verschachtelte Feld in die erste Ebene bringt. Sie können es so ändern, dass es abgeflacht wird, indem Sie sich an die ursprüngliche Platzierung der Schlüssel erinnern. Es wird auch davon ausgegangen, dass die Schlüssel auch für verschachtelte Objekte eindeutig sind. Ich hoffe es hilft.
Als Beispiel konvertiert es
in
quelle