source

오브젝트 속성 정렬 및 JSON.stringify

bestscript 2023. 3. 11. 09:03

오브젝트 속성 정렬 및 JSON.stringify

응용 프로그램에는 개체 배열이 매우 많아서 문자열화하여 디스크에 저장합니다.안타깝게도 어레이 내의 오브젝트가 조작되거나 교체될 때 오브젝트의 속성은 다른 순서(작성 순서?)로 나열됩니다.어레이에서 JSON.stringify()를 실행하여 저장하면 diff는 속성이 다른 순서로 나열되는 것을 보여 줍니다.이것은 diff 및 Marge 툴과 데이터를 더 Marge하려고 할 때 귀찮습니다.

stringify를 수행하기 전 또는 stringify 작업의 일부로 오브젝트의 속성을 알파벳 순으로 정렬하는 것이 이상적입니다.어레이 오브젝트를 조작하기 위한 코드가 여러 곳에 있으며, 항상 명시적인 순서로 속성을 작성하도록 변경하는 것은 어렵습니다.

제안해주시면 감사하겠습니다!

요약된 예:

obj = {}; obj.name="X"; obj.os="linux";
JSON.stringify(obj);
obj = {}; obj.os="linux"; obj.name="X";
JSON.stringify(obj);

이러한 2개의 문자열화 콜의 출력은 다르고, 데이터의 차이에 표시되지만, 애플리케이션의 속성 순서는 신경 쓰지 않습니다.그 물건들은 여러 가지 방법과 장소에서 만들어진다.

보다 심플하고 현대적이며 현재 브라우저가 지원하는 접근방식은 다음과 같습니다.

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

그러나 이 메서드는 참조되지 않은 중첩된 개체를 제거하며 배열 내의 개체에 적용되지 않습니다.다음과 같은 출력이 필요한 경우 정렬 개체를 평평하게 만들 수도 있습니다.

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

다음과 같이 할 수 있습니다.

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;
};
var myFlattenedObj = flattenObject(sortMyObj);
JSON.stringify(myFlattenedObj, Object.keys(myFlattenedObj).sort());

스스로 조정할 수 있는 것을 사용하여 프로그래밍 방식으로 이 작업을 수행하려면 개체 속성 이름을 배열에 밀어넣은 다음 배열을 알파벳 순으로 정렬하고 배열(올바른 순서)을 반복하여 개체에서 각 값을 해당 순서로 선택해야 합니다."HasOwnProperty"도 체크되어 있기 때문에 오브젝트 고유의 속성만 확실하게 가질 수 있습니다.다음은 예를 제시하겠습니다.

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

다시 말씀드리지만 알파벳 순으로 반복할 수 있습니다.

마지막으로, 가장 간단한 방법으로 이 라이브러리를 통해 전달된 모든 JSON을 재귀적으로 정렬할 수 있습니다.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));

산출량

{"a":3,"b":[{"x":4,"y":5,"z":6},7],"c":8}

왜 모든 키를 반복적으로 얻기 위해 현재의 최선의 답변의 복잡성이 필요한지 이해할 수 없습니다. 없는 한 그냥 될것요.JSON.stringify()두 번, 첫 번째에 모든 열쇠를 얻었고 두 번째에 실제로 일을 할 수 있었다.하면 '재귀'에 의해 처리됩니다.stringify이 그을 잘 있고, 유형예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예

function JSONstringifyOrder(obj, space)
{
    const allKeys = new Set();
    JSON.stringify(obj, (key, value) => (allKeys.add(key), value));
    return JSON.stringify(obj, Array.from(allKeys).sort(), space);
}

또는 이전 브라우저를 지원하는 경우:

function JSONstringifyOrder(obj, space)
{
    var allKeys = [];
    var seen = {};
    JSON.stringify(obj, function (key, value) {
        if (!(key in seen)) {
            allKeys.push(key);
            seen[key] = null;
        }
        return value;
    });
    allKeys.sort();
    return JSON.stringify(obj, allKeys, space);
}

JSON 세대(그리고 그렇게 들리는 것 같음)를 관리하고 있다면, 이 방법이 좋은 해결책이라고 생각합니다.json-stable-stringify

프로젝트 웹사이트:

문자열화된 결과에서 결정론적 해시를 가져오는 커스텀 정렬을 사용하는 결정론적 JSON.stringify()

생성된 JSON이 결정론적인 경우 쉽게 확산/병합할 수 있습니다.

을 두 할 수 .JSON.stringify():

JSON.stringify(obj, Object.keys(obj).sort())

JSON.stringify()오브젝트 키를 출력으로 정렬하기 위한 replacer 함수(깊이 중첩된 오브젝트 포함).

const replacer = (key, value) =>
value instanceof Object && !(value instanceof Array) ? 
    Object.keys(value)
    .sort()
    .reduce((sorted, key) => {
        sorted[key] = value[key];
        return sorted 
    }, {}) :
    value;

// Usage
// JSON.stringify({c: 1, a: { d: 0, c: 1, e: {a: 0, 1: 4}}}, replacer);

GitHub Gist 페이지 여기.

업데이트 2018-7-24:

이 버전은 중첩된 개체를 정렬하고 어레이도 지원합니다.

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

테스트 케이스:

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

  });

권장되지 않는 답변:

ES2016의 간결한 버전.https://stackoverflow.com/a/29622653/94148에서 @codename으로 크레딧을 발행합니다.

function orderedJsonStringify(o) {
  return JSON.stringify(Object.keys(o).sort().reduce((r, k) => (r[k] = o[k], r), {}));
}

이것은 새트팔 싱의 대답과 같다.

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"}"

재귀적이고 간단한 답변:

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

EcmaScript 2015에서 속성 이름별로 개체를 정렬할 수 있습니다.

function sortObjectByPropertyName(obj) {
    return Object.keys(obj).sort().reduce((c, d) => (c[d] = obj[d], c), {});
}

할 수 .toJSON출력을 커스터마이즈하는 데 사용할 수 있는 객체에 대한 기능.함수 내에서 특정 순서로 새 개체에 현재 속성을 추가하면 문자열화 시 해당 순서가 유지됩니다.

여기를 참조해 주세요.

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

JSON 데이터는 키로 액세스하도록 되어 있기 때문에 주문을 제어하는 기본 제공 방법은 없습니다.

다음은 jsfiddle과 작은 예를 제시하겠습니다.

http://jsfiddle.net/Eq2Yw/

를 .toJSON기능 - 성 function순 function function function function function function function function function function.이는 브라우저에 따라 다를 수 있습니다.즉, 주문은 사양에서 공식적으로 지원되지 않습니다.이 기능은 현재 버전의 Firefox에서 작동하지만 100% 강력한 솔루션을 원하는 경우 자체 문자열화 함수를 작성해야 할 수 있습니다.

편집:

stringify의 비결정론적 출력, 특히 브라우저의 차이에 대한 Daff의 상세 내용에 대한 SO 질문도 참조하십시오.

JSON 개체가 변경되지 않았음을 확인하는 방법은 무엇입니까?

@Jason Parham의 답변을 받아 개선했습니다.

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

이렇게 하면 어레이가 개체로 변환되는 문제가 해결되고 어레이를 정렬하는 방법도 정의할 수 있습니다.

예:

var data = { content: [{id: 3}, {id: 1}, {id: 2}] };
sortObject(data, (i1, i2) => i1.id - i2.id)

출력:

{content:[{id:1},{id:2},{id:3}]}

전에 '아까보다'에.stringify

const stringifySort = (key, value) => {
    if (!value || typeof value !== 'object' || Array.isArray(value)) return value;
    return Object.keys(value).sort().reduce((obj, key) => (obj[key]=value[key], obj), {});
};

JSON.stringify({name:"X", os:"linux"}, stringifySort);

어떤 이유로 인해 중첩된 개체에 대해 허용되는 답변이 작동하지 않습니다.이 일로 나는 내 자신의 코드를 만들 수 있었다.2019년 말이라 언어 내에서 몇 가지 선택지가 더 있습니다.

업데이트: 데이비드 펄롱의 답변은 저의 이전 시도에 대한 바람직한 접근법이라고 생각합니다.그리고 저는 그것을 회피했습니다.저는 Object.entries(...) 지원에 의존하기 때문에 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);

--

이력 참조를 위해 이 오래된 버전을 보관합니다.

오브젝트 내의 모든 키가 단순하고 평평한 배열로 동작하는 것을 발견했습니다.거의 모든 브라우저(예상대로 Edge나 Internet Explorer가 아님) 및 Node 12+에서는 Array.protype을 사용하여 매우 짧은 솔루션을 사용할 수 있습니다.platMap(...)을 사용할 수 있습니다.(lodash 상당량도 동작합니다.)저는 Safari, Chrome, Firefox에서만 테스트를 해봤지만, flatMap과 표준 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);
}

이를 통해 서드파티 의존관계 없이 스트링을 지정할 수 있으며 키와 값의 엔트리 쌍을 정렬하는 자체 정렬 알고리즘도 전달할 수 있으므로 키, 페이로드 또는 두 가지 조합을 기준으로 정렬할 수 있습니다.중첩된 개체, 배열 및 일반 이전 데이터 유형의 혼합에 대해 작동합니다.

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

인쇄:

{
  "a": 2,
  "b": 1,
  "c": {
    "x": 3,
    "y": [
      2048,
      1999,
      {
        "f": 5,
        "g": "help",
        "x": false
      }
    ],
    "z": 4
  }
}

오래된 JavaScript 엔진과의 호환성이 필요한 경우 flatMap 동작을 에뮬레이트하는 보다 상세한 버전을 사용할 수 있습니다.클라이언트는 적어도 ES5를 지원해야 하므로 Internet Explorer 8 이하를 지원하지 않습니다.

위와 같은 결과가 반환됩니다.

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

중첩된 개체에도 사용할 수 있는 추가 솔루션:

const myFunc = (key) =>
  JSON.stringify(key, (_, v) =>
    v.constructor === Object ? Object.entries(v).sort() : v
  );
  
const jsonFunc = JSON.stringify;
  
const obj1 = {
  key1: "value1",
  key2: {
    key3: "value2",
    key4: "value3",
  },
};
  
const obj2 = {
  key2: {
    key4: "value3",
    key3: "value2",
  },
  key1: "value1",
};

console.log(`JSON: ${jsonFunc(obj1) === jsonFunc(obj2)}`);
console.log(`My: ${myFunc(obj1) === myFunc(obj2)}`);

lodash, 중첩된 개체, 모든 개체 속성 값과 함께 작동합니다.

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)

오브젝트에 할당된 첫 번째 키가 다음에 의해 먼저 출력되는 것은 Chrome과 노드의 동작에 의존합니다.JSON.stringify.

결국 중첩된 개체 내의 모든 키를 캐시하는 배열이 필요합니다(그렇지 않으면 캐시되지 않은 키가 생략됩니다).두 번째 인수는 점 표기에는 관심이 없기 때문에 가장 오래된 답은 완전히 틀렸습니다.따라서 (Set을 사용하여) 답은 다음과 같습니다.

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

시험:

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

오브젝트를 정렬하는 기능을 만들어 콜백을 사용하였습니다.실제로 새로운 오브젝트를 만듭니다.

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

오브젝트로 호출합니다.

var obj = {
    name : "anu",
    os : "windows",
    value : 'msio',
};

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

JSON.stringify( result )

인쇄하는 방법{"value":"msio","os":"windows","name":"anu"}, 및 값을 사용하여 정렬합니다.

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

JSON.stringify( result )

인쇄하는 방법{"os":"windows","value":"msio","name":"anu"}

목록의 객체가 동일한 속성을 가지고 있지 않은 경우 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() );

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

// 아래와 같은 예.{}과(와) 같은 개체에 대해 각 레이어에서 키 정렬로 평탄하게 표시됩니다.JSON.stringify와 같은/또는 JSON.stringify로 평탄화된 배열, 숫자 또는 문자열의 경우.

FlatternInSort({ c:9, b: { y:4, z:2, e:9}}, F:4, a:[{j:8, h:3}, {a:3, b:7}})

"{F":4", "a":[{h":3", "j":8}, {"a":3", "b":7}], b":{"e":9", "y":4", "z":2}", "c":9}"

어레이 처리에 대한 AJP의 답변 확장:

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

아무도 로다쉬에 대해 언급하지 않았다니 놀랍다.isEqual기능.

두 값이 동일한지 여부를 확인하기 위해 두 값을 자세히 비교합니다.

주의: 이 방법에서는 어레이, 어레이 버퍼, 부울란, 날짜 개체, 오류 개체, 맵, 숫자, 개체 개체 개체, 정규식, 집합, 문자열, 기호 및 유형 배열의 비교를 지원합니다.개체 개체는 상속된 속성이 아닌 자체 열거형 속성으로 비교됩니다.기능과 DOM 노드는 ===와 같은 엄격한 평등에 의해 비교됩니다.

https://lodash.com/docs/4.17.11#isEqual

원래의 문제 - 키가 일관되지 않게 정렬되어 있는 것은 훌륭한 해결책입니다.물론 오브젝트 전체를 무작정 시리얼화하는 것이 아니라 충돌을 발견하면 중단됩니다.

라이브러리 전체를 Import하지 않게 하려면 , 다음의 순서에 따릅니다.

import { isEqual } from "lodash-es";

보너스 예:이 커스텀 연산자와 함께 RxJ에서도 사용할 수 있습니다.

export const distinctUntilEqualChanged = <T>(): MonoTypeOperatorFunction<T> => 
                                                pipe(distinctUntilChanged(isEqual));

클론 방법은 다음과 같습니다. 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;
}

매우 새롭지만 패키지로 동작하는 것 같습니다.json 파일은 정상입니다.

Chrome 디버거의 개체 모니터링과 혼동하지 마십시오.실제로는 정렬되지 않은 경우에도 오브젝트에 정렬된 키가 표시됩니다.개체를 문자열화하기 전에 정렬해야 합니다.

fast-json-stable-stringify와 같은 libs를 발견하기 전에는 이 방법을 사용하고 있었습니다.

import { flatten } from "flat";
import { set } from 'lodash/fp';

const sortJson = (jsonString) => {
  const object = JSON.parse(jsonString);
  const flatObject = flatten(object);
  const propsSorted = Object.entries(flatObject).map(([key, value]) => ({ key, value })).sort((a, b) => a.key.localeCompare(b.key));
  const objectSorted = propsSorted.reduce((object, { key, value }) => set(key, value, object), {});
  return JSON.stringify(objectSorted);
};


const originalJson = JSON.stringify({ c: { z: 3, x: 1, y: 2 }, a: true, b: [ 'a', 'b', 'c' ] });
console.log(sortJson(originalJson)); // {"a":true,"b":["a","b","c"],"c":{"x":1,"y":2,"z":3}} 

Array.sort당신에게 도움이 될 수 있는 방법.예를 들어 다음과 같습니다.

yourBigArray.sort(function(a,b){
    //custom sorting mechanism
});

언급URL : https://stackoverflow.com/questions/16167581/sort-object-properties-and-json-stringify