Saya melemparkan beberapa kode bersama-sama untuk meratakan dan un-meratakan objek JSON kompleks / bersarang. Berhasil, tapi agak lambat (memicu peringatan 'skrip panjang').
Untuk nama yang rata aku mau "." sebagai pembatas dan [INDEKS] untuk array.
Contoh:
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}
Saya membuat patokan yang ~ mensimulasikan use case saya http://jsfiddle.net/WSzec/
- Dapatkan objek JSON bersarang
- Ratakan
- Lihatlah dan mungkin memodifikasinya sambil diratakan
- Buka ratakan kembali ke format bersarang aslinya untuk dikirim
Saya ingin kode yang lebih cepat: Untuk klarifikasi, kode yang melengkapi tolok ukur JSFiddle ( http://jsfiddle.net/WSzec/ ) secara signifikan lebih cepat (~ 20% + lebih baik) di IE 9+, FF 24+, dan Chrome 29 +.
Berikut kode JavaScript yang relevan: Tercepat Saat Ini: 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;
}
EDIT 1 Dimodifikasi di atas untuk implementasi @Bergi yang saat ini tercepat. Selain itu, menggunakan ".indexOf" bukannya "regex.exec" sekitar 20% lebih cepat dalam FF tetapi 20% lebih lambat di Chrome; jadi saya akan tetap dengan regex karena lebih sederhana (inilah upaya saya menggunakan indexOf untuk mengganti http://exgmail.jsfiddle.net/WSzec/2/ ).
EDIT 2 Membangun ide @Bergi. Saya berhasil membuat versi non-regex yang lebih cepat (3x lebih cepat dalam FF dan ~ 10% lebih cepat di Chrome). http://jsfiddle.net/WSzec/6/ Dalam implementasi ini (saat ini) aturan untuk nama-nama kunci adalah sederhana, kunci tidak dapat dimulai dengan integer atau berisi periode.
Contoh:
- {"foo": {"bar": [0]}} => {"foo.bar.0": 0}
EDIT 3 Menambahkan pendekatan parsing jalur inline @AaditMShah (daripada String.split) membantu meningkatkan kinerja yang tidak merata. Saya sangat senang dengan peningkatan kinerja yang dicapai secara keseluruhan.
Jsfiddle dan jsperf terbaru:
sumber
[1].[1].[0]
terlihat salah bagiku. Apakah Anda yakin ini adalah hasil yang diinginkan?Jawaban:
Inilah implementasi saya yang jauh lebih pendek:
flatten
tidak banyak berubah (dan saya tidak yakin apakah Anda benar-benar membutuhkanisEmpty
kasus - kasus itu):Bersama-sama, mereka menjalankan patokan Anda sekitar setengah dari waktu (Opera 12.16: ~ 900ms bukannya ~ 1900ms, Chrome 29: ~ 800ms bukannya ~ 1600ms).
Catatan: Ini dan sebagian besar solusi lain yang dijawab di sini fokus pada kecepatan dan rentan terhadap polusi prototipe dan tidak akan digunakan pada benda yang tidak dipercaya.
sumber
result === data
tidak akan berhasil, mereka tidak pernah identik.Saya menulis dua fungsi ke
flatten
danunflatten
objek JSON.Ratakan objek JSON :
Kinerja :
Membatalkan objek JSON :
Kinerja :
Ratakan dan hapus merata objek JSON :
Secara keseluruhan solusi saya berkinerja sama baiknya atau bahkan lebih baik daripada solusi saat ini.
Kinerja :
Format output :
Objek yang diratakan menggunakan notasi titik untuk properti objek dan notasi braket untuk indeks array:
{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}
Menurut pendapat saya format ini lebih baik daripada hanya menggunakan notasi titik:
{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}
Keuntungan :
Kekurangan :
Demo JSFiddle saat ini memberikan nilai-nilai berikut sebagai output:
Demo JSFiddle saya yang diperbarui memberikan nilai-nilai berikut sebagai output:
Saya tidak begitu yakin apa artinya itu, jadi saya akan tetap dengan hasil jsPerf. Bagaimanapun jsPerf adalah utilitas pembandingan kinerja. JSFiddle tidak.
sumber
unflatten({"foo.__proto__.bar": 42})
3 ½ Tahun kemudian ...
Untuk proyek saya sendiri, saya ingin meratakan objek JSON dalam notasi mongoDB dot dan menghasilkan solusi sederhana:
Fitur dan / atau peringatan
{a: () => {}}
Anda mungkin tidak mendapatkan apa yang Anda inginkan!{a: {}, b: []}
diratakan{}
.sumber
{"x": "abc\"{x}\"yz"}
menjadi{ "x": "abc"{,"x",}"yz"}
yang tidak valid.Versi ES6:
Contoh:
sumber
Date
, ada ide bagaimana cara melakukannya? Misalnya, denganflatten({a: {b: new Date()}});
Berikut ini pendekatan lain yang berjalan lebih lambat (sekitar 1000 ms) dari jawaban di atas, tetapi memiliki ide yang menarik :-)
Alih-alih mengulangi setiap rantai properti, ia hanya mengambil properti terakhir dan menggunakan tabel pencarian untuk sisanya untuk menyimpan hasil antara. Tabel pencarian ini akan diulangi sampai tidak ada rantai properti yang tersisa dan semua nilai berada pada properti yang tidak dipatenkan.
Saat ini menggunakan
data
parameter input untuk tabel, dan menempatkan banyak properti di atasnya - versi non-destruktif juga dimungkinkan. MungkinlastIndexOf
penggunaan cerdas berkinerja lebih baik daripada regex (tergantung pada mesin regex).Lihat beraksi di sini .
sumber
unflatten
objek rata dengan benar. Sebagai contoh, pertimbangkan array[1,[2,[3,4],5],6]
.flatten
Fungsi Anda meratakan objek ini ke{"[0]":1,"[1][0]":2,"[1][1][0]":3,"[1][1][1]":4,"[1][2]":5,"[2]":6}
.unflatten
Namun, fungsi Anda secara keliru membatalkan objek rata[1,[null,[3,4]],6]
. Alasan ini terjadi adalah karena pernyataandelete data[p]
yang secara prematur menghapus nilai menengah[2,null,5]
sebelum[3,4]
ditambahkan ke dalamnya. Gunakan tumpukan untuk menyelesaikannya. :-)Anda dapat menggunakan https://github.com/hughsk/flat
Contoh dari dok
sumber
Kode ini secara mendatar meratakan objek JSON.
Saya memasukkan mekanisme pengaturan waktu saya dalam kode dan memberi saya 1 ms tetapi saya tidak yakin apakah itu yang paling akurat.
Keluaran:
sumber
typeof some === 'object'
lebih cepat makasome instanceof Object
sejak pemeriksaan pertama dilakukan di O1 sementara yang kedua di Di mana n adalah panjang rantai pewarisan (Objek akan selalu menjadi yang terakhir di sana).Saya menambahkan +/- 10-15% efisiensi untuk jawaban yang dipilih oleh refactoring kode minor dan memindahkan fungsi rekursif di luar namespace fungsi.
Lihat pertanyaan saya: Apakah fungsi namespace dievaluasi kembali pada setiap panggilan? untuk alasan ini memperlambat fungsi bersarang.
Lihat patokan .
sumber
Ini milik saya. Ini berjalan dalam <2ms dalam Google Apps Script pada objek yang cukup besar. Ini menggunakan tanda hubung bukan titik untuk separator, dan tidak menangani array khusus seperti dalam pertanyaan penanya, tapi ini yang saya inginkan untuk saya gunakan.
Contoh:
Contoh output:
sumber
Gunakan perpustakaan ini:
Penggunaan (dari https://www.npmjs.com/package/flat ):
Meratakan:
Batalkan rata:
sumber
Saya ingin menambahkan versi baru case rata (ini yang saya butuhkan :)) yang, menurut penyelidikan saya dengan jsFiddler di atas, sedikit lebih cepat daripada yang saat ini dipilih. Selain itu, saya pribadi melihat cuplikan ini sedikit lebih mudah dibaca, yang tentu saja penting untuk proyek multi-pengembang.
sumber
Berikut adalah beberapa kode yang saya tulis untuk meratakan objek yang sedang saya kerjakan. Itu menciptakan kelas baru yang mengambil setiap bidang bersarang dan membawanya ke lapisan pertama. Anda dapat memodifikasinya menjadi tidak rata dengan mengingat penempatan kunci yang asli. Ini juga mengasumsikan kunci unik bahkan di seluruh objek bersarang. Semoga ini bisa membantu.
Sebagai contoh, itu mengkonversi
ke
sumber