sort object properties and JSON.stringify

后端 未结 22 2165
南方客
南方客 2020-11-28 05:44

My application has a large array of objects, which I stringify and save them to the disk. Unfortunately, when the objects in the array are manipulated, and sometimes replac

相关标签:
22条回答
  • 2020-11-28 06:04

    You can add a custom toJSON function to your object which you can use to customise the output. Inside the function, adding current properties to a new object in a specific order should preserve that order when stringified.

    See here:

    https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/JSON/stringify

    There's no in-built method for controlling ordering because JSON data is meant to be accessed by keys.

    Here's a jsfiddle with a small example:

    http://jsfiddle.net/Eq2Yw/

    Try commenting out the toJSON function - the order of the properties is reversed. Please be aware that this may be browser-specific, i.e. ordering is not officially supported in the specification. It works in the current version of Firefox, but if you want a 100% robust solution, you may have to write your own stringifier function.

    Edit:

    Also see this SO question regarding stringify's non-deterministic output, especially Daff's details about browser differences:

    How to deterministically verify that a JSON object hasn't been modified?

    0 讨论(0)
  • 2020-11-28 06:04

    I made a function to sort object, and with callback .. which actually create a new object

    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;
        },{});
    }
    

    and call it with object .

    var obj = {
        name : "anu",
        os : "windows",
        value : 'msio',
    };
    
    var result = sortObj( obj , function( a, b ){
        return a.key < b.key  ;    
    });
    
    JSON.stringify( result )
    

    which prints {"value":"msio","os":"windows","name":"anu"} , and for sorting with value .

    var result = sortObj( obj , function( a, b ){
        return a.value < b.value  ;    
    });
    
    JSON.stringify( result )
    

    which prints {"os":"windows","value":"msio","name":"anu"}

    0 讨论(0)
  • 2020-11-28 06:05

    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;
    
    0 讨论(0)
  • 2020-11-28 06:05

    There is Array.sort method which can be helpful for you. For example:

    yourBigArray.sort(function(a,b){
        //custom sorting mechanism
    });
    
    0 讨论(0)
  • 2020-11-28 06:07

    I think that if you are in control of the JSON generation (and it sounds like you are), then for your purposes this might be a good solution: json-stable-stringify

    From the project website:

    deterministic JSON.stringify() with custom sorting to get deterministic hashes from stringified results

    If the JSON produced is deterministic you should be able to easily diff/merge it.

    0 讨论(0)
  • 2020-11-28 06:08

    The simpler, modern and currently browser supported approach is simply this:

    JSON.stringify(sortMyObj, Object.keys(sortMyObj).sort());
    

    However, this method does remove any nested objects that aren't referenced and does not apply to objects within arrays. You will want to flatten the sorting object as well if you want something like this output:

    {"a":{"h":4,"z":3},"b":2,"c":1}
    

    You can do that with this:

    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());
    

    To do it programmatically with something you can tweak yourself, you need to push the object property names into an array, then sort the array alphabetically and iterate through that array (which will be in the right order) and select each value from the object in that order. "hasOwnProperty" is checked also so you definitely have only the object's own properties. Here's an example:

    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
    });
    

    Again, this should guarantee that you iterate through in alphabetical order.

    Finally, taking it further for the simplest way, this library will recursively allow you to sort any JSON you pass into it: 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));
    

    Output

    {"a":3,"b":[{"x":4,"y":5,"z":6},7],"c":8}
    
    0 讨论(0)
提交回复
热议问题