Aplikasi saya memiliki banyak sekali objek, yang saya rangkai dan simpan ke disk. Sayangnya, ketika objek dalam array dimanipulasi, dan terkadang diganti, properti pada objek terdaftar dalam urutan yang berbeda (urutan pembuatannya?). Ketika saya melakukan JSON.stringify () pada array dan menyimpannya, diff menunjukkan properti yang terdaftar dalam urutan yang berbeda, yang mengganggu ketika mencoba menggabungkan data lebih jauh dengan alat diff dan penggabungan.
Idealnya saya ingin mengurutkan properti objek dalam urutan abjad sebelum melakukan stringify, atau sebagai bagian dari operasi stringify. Ada kode untuk memanipulasi objek array di banyak tempat, dan mengubahnya untuk selalu membuat properti dalam urutan eksplisit akan sulit.
Saran akan sangat diterima!
Contoh kental:
obj = {}; obj.name="X"; obj.os="linux";
JSON.stringify(obj);
obj = {}; obj.os="linux"; obj.name="X";
JSON.stringify(obj);
Output dari dua panggilan stringify ini berbeda, dan muncul dalam perbedaan data saya, tetapi aplikasi saya tidak peduli tentang pengurutan properti. Benda-benda tersebut dibangun dengan berbagai cara dan tempat.
sumber
Jawaban:
Pendekatan yang lebih sederhana, modern, dan saat ini didukung browser hanyalah sebagai berikut:
JSON.stringify(sortMyObj, Object.keys(sortMyObj).sort());
Namun, metode ini menghapus objek bertingkat yang tidak direferensikan dan tidak berlaku untuk objek dalam array. Anda juga ingin meratakan objek penyortiran jika Anda menginginkan sesuatu seperti keluaran ini:
{"a":{"h":4,"z":3},"b":2,"c":1}
Anda dapat melakukannya dengan ini:
var flattenObject = function(ob) { var toReturn = {}; for (var i in ob) { if (!ob.hasOwnProperty(i)) continue; if ((typeof ob[i]) == 'object') { var flatObject = flattenObject(ob[i]); for (var x in flatObject) { if (!flatObject.hasOwnProperty(x)) continue; toReturn[i + '.' + x] = flatObject[x]; } } else { toReturn[i] = ob[i]; } } return toReturn; }; JSON.stringify(sortMyObj, Object.keys(flattenObject(sortMyObj)).sort());
Untuk melakukannya secara terprogram dengan sesuatu yang dapat Anda sesuaikan sendiri, Anda perlu memasukkan nama properti objek ke dalam larik, lalu mengurutkan larik secara alfabet dan mengulangi larik tersebut (yang akan berada dalam urutan yang benar) dan memilih setiap nilai dari objek di pesanan itu. "hasOwnProperty" juga dicentang jadi Anda pasti hanya memiliki properti objek itu sendiri. Berikut contohnya:
var obj = {"a":1,"b":2,"c":3}; function iterateObjectAlphabetically(obj, callback) { var arr = [], i; for (i in obj) { if (obj.hasOwnProperty(i)) { arr.push(i); } } arr.sort(); for (i = 0; i < arr.length; i++) { var key = obj[arr[i]]; //console.log( obj[arr[i]] ); //here is the sorted value //do what you want with the object property if (callback) { // callback returns arguments for value, key and original object callback(obj[arr[i]], arr[i], obj); } } } iterateObjectAlphabetically(obj, function(val, key, obj) { //do something here });
Sekali lagi, ini akan menjamin bahwa Anda mengulang dalam urutan abjad.
Terakhir, melangkah lebih jauh untuk cara yang paling sederhana, pustaka ini secara rekursif akan memungkinkan Anda untuk mengurutkan JSON apa pun yang Anda berikan ke dalamnya: https://www.npmjs.com/package/json-stable-stringify
var stringify = require('json-stable-stringify'); var obj = { c: 8, b: [{z:6,y:5,x:4},7], a: 3 }; console.log(stringify(obj));
Keluaran
{"a":3,"b":[{"x":4,"y":5,"z":6},7],"c":8}
sumber
obj[i]
perulangan for karenai
merupakan integer, dan nama propertinya belum tentu (oleh karena itu pertanyaan ini). Seharusnya begituobj[arr[i]]
.iterateObjectAlphabetically
menjadi fungsi yang dapat digunakan kembali. Tanpa callback, 'kode payload' harus berada di dalam fungsi itu sendiri. Saya pikir ini adalah solusi yang sangat elegan dan yang digunakan di banyak perpustakaan dan inti JS itu sendiri. Misalnya Array.forEach .Saya pikir jika Anda mengendalikan generasi JSON (dan kedengarannya seperti Anda), maka untuk tujuan Anda ini mungkin solusi yang baik: json-stable-stringify
Dari situs proyek:
Jika JSON yang dihasilkan bersifat deterministik, Anda seharusnya dapat dengan mudah melakukan diff / menggabungkannya.
sumber
Anda bisa meneruskan array yang diurutkan dari nama properti sebagai argumen kedua dari
JSON.stringify()
:JSON.stringify(obj, Object.keys(obj).sort())
sumber
JSON.stringify()
dipanggilreplacer
dan dapat berupa array. Ini digunakan untuk membangunPropertyList
yang kemudian digunakanSerializeJSONObject()
untuk menambahkan properti dalam urutan itu. Ini didokumentasikan sejak ECMAScript 5.> JSON.stringify({a: {c: 1, b: 2}}, ['a']) '{"a":{}}'
Satu cara (hacky) untuk membangun daftar semua kunci yang relevan adalah dengan menggunakan JSON.stringify untuk melintasi objek:function orderedStringify(obj) { const allKeys = []; JSON.stringify(obj, (k, v) => { allKeys.push(k); return v; }); return JSON.stringify(obj, allKeys.sort()); }
Contoh:> orderedStringify({a: {c: 1, b: 2}}) '{"a":{"b":2,"c":1}}'
Saya tidak mengerti mengapa kompleksitas jawaban terbaik saat ini diperlukan, untuk mendapatkan semua kunci secara rekursif. Kecuali jika kinerja yang sempurna diperlukan, bagi saya tampaknya kita hanya dapat menelepon
JSON.stringify()
dua kali, pertama kali untuk mendapatkan semua kunci, dan kedua, untuk benar-benar melakukan pekerjaan itu. Dengan cara itu, semua kompleksitas rekursi ditangani olehstringify
, dan kita tahu bahwa rekursi mengetahui barangnya, dan cara menangani setiap jenis objek:function JSONstringifyOrder( obj, space ) { var allKeys = []; JSON.stringify( obj, function( key, value ){ allKeys.push( key ); return value; } ) allKeys.sort(); return JSON.stringify( obj, allKeys, space ); }
sumber
Object.keys()
tidak rekursif, jadi jika Anda memiliki objek seperti{a: "A", b: {c: "C"} }
dan Anda memanggil Object.keys di atasnya, Anda hanya akan mendapatkan kuncia
danb
, tetapi tidakc
.JSON.stringify
mengetahui segala sesuatu tentang rekursi pada setiap jenis objek yang ditangani oleh proses serialisasi JSON, baik itu seperti objek atau array (dan itu sudah mengimplementasikan logika untuk mengenali keduanya), jadi itu harus menangani semuanya dengan benar untuk kita.Perbarui 2018-7-24:
Versi ini mengurutkan objek bersarang dan mendukung larik juga:
function sortObjByKey(value) { return (typeof value === 'object') ? (Array.isArray(value) ? value.map(sortObjByKey) : Object.keys(value).sort().reduce( (o, key) => { const v = value[key]; o[key] = sortObjByKey(v); return o; }, {}) ) : value; } function orderedJsonStringify(obj) { return JSON.stringify(sortObjByKey(obj)); }
Kasus cobaan:
describe('orderedJsonStringify', () => { it('make properties in order', () => { const obj = { name: 'foo', arr: [ { x: 1, y: 2 }, { y: 4, x: 3 }, ], value: { y: 2, x: 1, }, }; expect(orderedJsonStringify(obj)) .to.equal('{"arr":[{"x":1,"y":2},{"x":3,"y":4}],"name":"foo","value":{"x":1,"y":2}}'); }); it('support array', () => { const obj = [ { x: 1, y: 2 }, { y: 4, x: 3 }, ]; expect(orderedJsonStringify(obj)) .to.equal('[{"x":1,"y":2},{"x":3,"y":4}]'); }); });
Jawaban yang tidak berlaku lagi:
Versi ringkas di ES2016. Penghargaan untuk @codename, dari https://stackoverflow.com/a/29622653/94148
function orderedJsonStringify(o) { return JSON.stringify(Object.keys(o).sort().reduce((r, k) => (r[k] = o[k], r), {})); }
sumber
function orderedJsonStringify(o) { return JSON.stringify(Object.keys(o).sort().reduce((r, k) => (r[k] = o[k], r), {})); }
sortObjByKey()
memeriksa referensi melingkar, jadi berhati-hatilah, ini mungkin menggantung dalam loop tak terbatas tergantung pada data masukan. Contoh:var objA = {}; var objB = {objA: objA}; objA.objB = objB;
->sortObjByKey(objA);
->VM59:6 Uncaught RangeError: Maximum call stack size exceeded
https://gist.github.com/davidfurlong/463a83a33b70a3b6618e97ec9679e490
const replacer = (key, value) => value instanceof Object && !(value instanceof Array) ? Object.keys(value) .sort() .reduce((sorted, key) => { sorted[key] = value[key]; return sorted }, {}) : value;
sumber
Ini sama dengan jawaban Satpal Singh
function stringifyJSON(obj){ keys = []; if(obj){ for(var key in obj){ keys.push(key); } } keys.sort(); var tObj = {}; var key; for(var index in keys){ key = keys[index]; tObj[ key ] = obj[ key ]; } return JSON.stringify(tObj); } obj1 = {}; obj1.os="linux"; obj1.name="X"; stringifyJSON(obj1); //returns "{"name":"X","os":"linux"}" obj2 = {}; obj2.name="X"; obj2.os="linux"; stringifyJSON(obj2); //returns "{"name":"X","os":"linux"}"
sumber
Anda dapat menambahkan
toJSON
fungsi khusus ke objek Anda yang dapat Anda gunakan untuk menyesuaikan keluaran. Di dalam fungsi, menambahkan properti saat ini ke objek baru dalam urutan tertentu harus mempertahankan urutan itu saat dirangkai.Lihat disini:
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/JSON/stringify
Tidak ada metode bawaan untuk mengontrol pengurutan karena data JSON dimaksudkan untuk diakses oleh kunci.
Berikut adalah jsfiddle dengan contoh kecil:
http://jsfiddle.net/Eq2Yw/
Cobalah mengomentari
toJSON
fungsinya - urutan propertinya dibalik. Perlu diketahui bahwa ini mungkin khusus browser, yaitu pemesanan tidak didukung secara resmi dalam spesifikasi. Ini berfungsi di versi Firefox saat ini, tetapi jika Anda menginginkan solusi yang 100% kuat, Anda mungkin harus menulis fungsi stringifier Anda sendiri.Edit:
Lihat juga pertanyaan SO ini tentang keluaran non-deterministik stringify, terutama detail Daff tentang perbedaan browser:
Bagaimana cara memverifikasi secara deterministik bahwa objek JSON belum dimodifikasi?
sumber
Jawaban rekursif dan sederhana:
function sortObject(obj) { if(typeof obj !== 'object') return obj var temp = {}; var keys = []; for(var key in obj) keys.push(key); keys.sort(); for(var index in keys) temp[keys[index]] = sortObject(obj[keys[index]]); return temp; } var str = JSON.stringify(sortObject(obj), undefined, 4);
sumber
reorder
harus diganti namanya menjadisortObject
dan ini tidak menangani lariktypeof arr === "object"
itu akan mengubah array menjadi objek. Misalnyavar obj = {foo: ["bar", "baz"]}
akan{ "foo": { "0": "bar", "1": "baz"} }
if(obj.constructor.prototype !== Object.prototype)
Anda dapat mengurutkan objek berdasarkan nama properti di EcmaScript 2015
function sortObjectByPropertyName(obj) { return Object.keys(obj).sort().reduce((c, d) => (c[d] = obj[d], c), {}); }
sumber
sortObjectPropertiesByName()
atau lebih sederhanasortPropertiesByName()
.Saya mengambil jawaban dari @Jason Parham dan membuat beberapa perbaikan
function sortObject(obj, arraySorter) { if(typeof obj !== 'object') return obj if (Array.isArray(obj)) { if (arraySorter) { obj.sort(arraySorter); } for (var i = 0; i < obj.length; i++) { obj[i] = sortObject(obj[i], arraySorter); } return obj; } var temp = {}; var keys = []; for(var key in obj) keys.push(key); keys.sort(); for(var index in keys) temp[keys[index]] = sortObject(obj[keys[index]], arraySorter); return temp; }
Ini memperbaiki masalah larik yang diubah menjadi objek, dan ini juga memungkinkan Anda untuk menentukan cara mengurutkan larik.
Contoh:
var data = { content: [{id: 3}, {id: 1}, {id: 2}] }; sortObject(data, (i1, i2) => i1.id - i2.id)
keluaran:
{content:[{id:1},{id:2},{id:3}]}
sumber
Jawaban yang diterima tidak berfungsi untuk saya untuk objek bersarang karena beberapa alasan. Ini membuat saya membuat kode saya sendiri. Karena akhir 2019 ketika saya menulis ini, ada beberapa opsi lagi yang tersedia dalam bahasa ini.
Pembaruan: Saya percaya jawaban David Furlong adalah pendekatan yang lebih disukai untuk upaya saya sebelumnya, dan saya telah mengesampingkannya. Milik saya mengandalkan dukungan untuk Object.entries (...), jadi tidak ada dukungan Internet Explorer.
function normalize(sortingFunction) { return function(key, value) { if (typeof value === 'object' && !Array.isArray(value)) { return Object .entries(value) .sort(sortingFunction || undefined) .reduce((acc, entry) => { acc[entry[0]] = entry[1]; return acc; }, {}); } return value; } } JSON.stringify(obj, normalize(), 2);
-
MEMPERTAHANKAN VERSI LAMA INI UNTUK REFERENSI SEJARAH
Saya menemukan bahwa array datar sederhana dari semua kunci di objek akan berfungsi. Di hampir semua browser (bukan Edge atau Internet explorer, dapat diprediksi) dan Node 12+ ada solusi yang cukup singkat sekarang karena Array.prototype.flatMap (...) tersedia. (Setara lodash akan berfungsi juga.) Saya hanya menguji di Safari, Chrome, dan Firefox, tetapi saya tidak melihat alasan mengapa itu tidak akan berfungsi di tempat lain yang mendukung flatMap dan standar JSON.stringify (...) .
function flattenEntries([key, value]) { return (typeof value !== 'object') ? [ [ key, value ] ] : [ [ key, value ], ...Object.entries(value).flatMap(flattenEntries) ]; } function sortedStringify(obj, sorter, indent = 2) { const allEntries = Object.entries(obj).flatMap(flattenEntries); const sorted = allEntries.sort(sorter || undefined).map(entry => entry[0]); return JSON.stringify(obj, sorted, indent); }
Dengan ini, Anda dapat merangkai tanpa dependensi pihak ketiga dan bahkan meneruskan algoritme pengurutan Anda sendiri yang mengurutkan pasangan entri nilai kunci, sehingga Anda dapat mengurutkan berdasarkan kunci, payload, atau kombinasi keduanya. Berfungsi untuk objek bersarang, larik, dan campuran apa pun dari tipe data lama biasa.
const obj = { "c": { "z": 4, "x": 3, "y": [ 2048, 1999, { "x": false, "g": "help", "f": 5 } ] }, "a": 2, "b": 1 }; console.log(sortedStringify(obj, null, 2));
Cetakan:
{ "a": 2, "b": 1, "c": { "x": 3, "y": [ 2048, 1999, { "f": 5, "g": "help", "x": false } ], "z": 4 } }
Jika Anda harus memiliki kompatibilitas dengan mesin JavaScript yang lebih lama , Anda dapat menggunakan versi yang sedikit lebih panjang ini yang meniru perilaku flatMap. Klien harus mendukung setidaknya ES5, jadi tidak ada Internet Explorer 8 atau yang lebih rendah.
Ini akan mengembalikan hasil yang sama seperti di atas.
function flattenEntries([key, value]) { if (typeof value !== 'object') { return [ [ key, value ] ]; } const nestedEntries = Object .entries(value) .map(flattenEntries) .reduce((acc, arr) => acc.concat(arr), []); nestedEntries.unshift([ key, value ]); return nestedEntries; } function sortedStringify(obj, sorter, indent = 2) { const sortedKeys = Object .entries(obj) .map(flattenEntries) .reduce((acc, arr) => acc.concat(arr), []) .sort(sorter || undefined) .map(entry => entry[0]); return JSON.stringify(obj, sortedKeys, indent); }
sumber
Bekerja dengan lodash, objek bersarang, nilai apa pun dari atribut objek:
function sort(myObj) { var sortedObj = {}; Object.keys(myObj).sort().forEach(key => { sortedObj[key] = _.isPlainObject(myObj[key]) ? sort(myObj[key]) : myObj[key] }) return sortedObj; } JSON.stringify(sort(yourObj), null, 2)
Ini bergantung pada perilaku Chrome dan Node di mana kunci pertama yang ditetapkan ke suatu objek dikeluarkan pertama oleh
JSON.stringify
.sumber
Mencoba:
function obj(){ this.name = ''; this.os = ''; } a = new obj(); a.name = 'X', a.os = 'linux'; JSON.stringify(a); b = new obj(); b.os = 'linux'; b.name = 'X', JSON.stringify(b);
sumber
Saya membuat fungsi untuk mengurutkan objek, dan dengan callback .. yang sebenarnya membuat objek baru
function sortObj( obj , callback ) { var r = [] ; for ( var i in obj ){ if ( obj.hasOwnProperty( i ) ) { r.push( { key: i , value : obj[i] } ); } } return r.sort( callback ).reduce( function( obj , n ){ obj[ n.key ] = n.value ; return obj; },{}); }
dan menyebutnya dengan objek.
var obj = { name : "anu", os : "windows", value : 'msio', }; var result = sortObj( obj , function( a, b ){ return a.key < b.key ; }); JSON.stringify( result )
yang mencetak
{"value":"msio","os":"windows","name":"anu"}
, dan untuk menyortir dengan nilai.var result = sortObj( obj , function( a, b ){ return a.value < b.value ; }); JSON.stringify( result )
yang mencetak
{"os":"windows","value":"msio","name":"anu"}
sumber
Jika objek dalam daftar tidak memiliki properti yang sama, buat objek master gabungan sebelum stringify:
let arr=[ <object1>, <object2>, ... ] let o = {} for ( let i = 0; i < arr.length; i++ ) { Object.assign( o, arr[i] ); } JSON.stringify( arr, Object.keys( o ).sort() );
sumber
function FlatternInSort( obj ) { if( typeof obj === 'object' ) { if( obj.constructor === Object ) { //here use underscore.js let PaireStr = _( obj ).chain().pairs().sortBy( p => p[0] ).map( p => p.map( FlatternInSort ).join( ':' )).value().join( ',' ); return '{' + PaireStr + '}'; } return '[' + obj.map( FlatternInSort ).join( ',' ) + ']'; } return JSON.stringify( obj ); }
// contoh seperti di bawah ini. dalam setiap lapisan, untuk objek seperti {}, diratakan dalam urutan kunci. untuk array, angka atau string, diratakan seperti / dengan JSON.stringify.
sumber
Memperluas jawaban AJP, untuk menangani array:
function sort(myObj) { var sortedObj = {}; Object.keys(myObj).sort().forEach(key => { sortedObj[key] = _.isPlainObject(myObj[key]) ? sort(myObj[key]) : _.isArray(myObj[key])? myObj[key].map(sort) : myObj[key] }) return sortedObj; }
sumber
Terkejut tidak ada yang menyebutkan
isEqual
fungsi lodash .Dengan masalah awal - kunci yang diurutkan secara tidak konsisten - ini adalah solusi yang bagus - dan tentu saja ini hanya akan berhenti jika menemukan konflik alih-alih menyusun seluruh objek secara membabi buta.
Untuk menghindari mengimpor seluruh pustaka Anda melakukan ini:
import { isEqual } from "lodash-es";
Contoh bonus: Anda juga dapat menggunakan ini dengan RxJS dengan operator kustom ini
export const distinctUntilEqualChanged = <T>(): MonoTypeOperatorFunction<T> => pipe(distinctUntilChanged(isEqual));
sumber
Bagaimanapun, ini membutuhkan Array yang menyimpan semua kunci dalam objek bersarang (jika tidak maka akan menghilangkan kunci yang tidak di-cache.) Jawaban terlama salah, karena argumen kedua tidak peduli dengan notasi titik. Jadi, jawabannya (menggunakan Set) menjadi.
function stableStringify (obj) { const keys = new Set() const getAndSortKeys = (a) => { if (a) { if (typeof a === 'object' && a.toString() === '[object Object]') { Object.keys(a).map((k) => { keys.add(k) getAndSortKeys(a[k]) }) } else if (Array.isArray(a)) { a.map((el) => getAndSortKeys(el)) } } } getAndSortKeys(obj) return JSON.stringify(obj, Array.from(keys).sort()) }
sumber
Berikut adalah pendekatan klon ... kloning objek sebelum mengonversi ke json:
function sort(o: any): any { if (null === o) return o; if (undefined === o) return o; if (typeof o !== "object") return o; if (Array.isArray(o)) { return o.map((item) => sort(item)); } const keys = Object.keys(o).sort(); const result = <any>{}; keys.forEach((k) => (result[k] = sort(o[k]))); return result; }
Jika sangat baru tetapi tampaknya berfungsi pada file package.json baik-baik saja.
sumber
Ada
Array.sort
metode yang bisa membantu Anda. Sebagai contoh:yourBigArray.sort(function(a,b){ //custom sorting mechanism });
sumber