programing

중첩된 JavaScript 개체를 평탄화/평탄화 해제하는 가장 빠른 방법

yoursource 2022. 11. 21. 23:01
반응형

중첩된 JavaScript 개체를 평탄화/평탄화 해제하는 가장 빠른 방법

복잡한 자바스크립트 오브젝트를 평평하게 하거나 평평하게 하지 않기 위해 코드를 조합했습니다.동작하지만, 조금 느립니다('긴 스크립트' 경고 트리거).

평탄한 이름의 경우 구분 기호로 "."를 사용하고 배열의 경우 [INDEX]를 사용합니다.

예:

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}

사용 사례를 시뮬레이션하는 벤치마크를 작성했습니다.http://jsfiddle.net/WSzec/

  • 중첩된 개체 가져오기
  • 평평하게 하다
  • 훑어보고 평탄한 상태에서 수정할 수 있습니다.
  • 원래 네스트된 포맷으로 되돌려서 출하합니다.

더 빠른 코드를 원합니다.명확히 하기 위해 IE 9+, FF 24+ 및 Chrome 29+에서는 JSFiddle 벤치마크를 완료하는 코드(http://jsfiddle.net/WSzec/)가 훨씬 더 빠릅니다(~20% 이상이면 좋습니다).

다음은 관련 JavaScript 코드입니다.현재 가장 빠른 속도: http://jsfiddle.net/WSzec/6/

var 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[""];
}
var 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;
}

편집 1 위의 내용을 현재 가장 빠른 @Bergi의 구현으로 변경.한편, 「regex.exec」 대신에 「.indexOf」를 사용하는 것이 FF에서는 약 20% 고속이지만, Chrome에서는 약 20% 저속입니다.따라서 regex가 더 심플하기 때문에 regex를 계속 사용합니다(여기에서는 regex http://jsfiddle.net/WSzec/2/)를 대체하기 위해 indexOf를 사용하려고 합니다.

편집 2 @Bergi의 아이디어에 따라 나는 더 빠른 비정규 버전(FF에서는 3배, Chrome에서는 최대 10%)을 만들 수 있었습니다.http://jsfiddle.net/WSzec/6/ 이 (현재의) 실장에서는, 키명의 룰은 간단하게, 키는 정수로 개시할 수 없고, 마침표를 포함할 수 없습니다.

예:

  • {"foo":{"bar":[0]}} => {"foo.bar.0":0}

편집 3 @Aadit 추가(String.split이 아닌) MSHA의 인라인 경로 구문 분석 접근 방식을 통해 플랫텐 해제 성능이 향상되었습니다.전반적인 실적 향상에 매우 만족합니다.

최신 jsfiddle 및 jsperf:

http://jsfiddle.net/WSzec/14/

http://jsperf.com/flatten-un-flatten/4

다음은 훨씬 짧은 구현입니다.

Object.unflatten = function(data) {
    "use strict";
    if (Object(data) !== data || Array.isArray(data))
        return data;
    var regex = /\.?([^.\[\]]+)|\[(\d+)\]/g,
        resultholder = {};
    for (var p in data) {
        var cur = resultholder,
            prop = "",
            m;
        while (m = regex.exec(p)) {
            cur = cur[prop] || (cur[prop] = (m[2] ? [] : {}));
            prop = m[2] || m[1];
        }
        cur[prop] = data[p];
    }
    return resultholder[""] || resultholder;
};

flatten별로 변하지 않았습니다(그리고 정말 필요한지는 잘 모르겠습니다).isEmpty케이스) :

Object.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 + "[" + 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 && prop)
                result[prop] = {};
        }
    }
    recurse(data, "");
    return result;
}

두 가지를 합치면 벤치마크 실행 시간이 절반으로 단축됩니다(Opera 12.16: ~900ms, Chrome 29: ~1600ms 대신 ~800ms).

주의: 이 솔루션과 여기에 답변된 대부분의 다른 솔루션은 속도에 중점을 두고 있으며 시제품 오염의 영향을 받기 쉬우며 신뢰할 수 없는 물체에 사용하지 마십시오.

.flatten ★★★★★★★★★★★★★★★★★」unflattenJSON 브 j j


JSON 개체 평탄화:

var flatten = (function (isArray, wrapped) {
    return function (table) {
        return reduce("", {}, table);
    };

    function reduce(path, accumulator, table) {
        if (isArray(table)) {
            var length = table.length;

            if (length) {
                var index = 0;

                while (index < length) {
                    var property = path + "[" + index + "]", item = table[index++];
                    if (wrapped(item) !== item) accumulator[property] = item;
                    else reduce(property, accumulator, item);
                }
            } else accumulator[path] = table;
        } else {
            var empty = true;

            if (path) {
                for (var property in table) {
                    var item = table[property], property = path + "." + property, empty = false;
                    if (wrapped(item) !== item) accumulator[property] = item;
                    else reduce(property, accumulator, item);
                }
            } else {
                for (var property in table) {
                    var item = table[property], empty = false;
                    if (wrapped(item) !== item) accumulator[property] = item;
                    else reduce(property, accumulator, item);
                }
            }

            if (empty) accumulator[path] = table;
        }

        return accumulator;
    }
}(Array.isArray, Object));

퍼포먼스:

  1. 현재 Opera의 솔루션보다 빠릅니다.현재 솔루션은 Opera에서 26% 느립니다.
  2. 파이어폭스의 현재 솔루션보다 빠릅니다.현재 솔루션은 Firefox에서 9% 느립니다.
  3. 현재 크롬의 솔루션보다 빠릅니다.현재의 솔루션은 크롬이 29% 느립니다.

JSON 오브젝트의 플랫을 해제합니다.

function unflatten(table) {
    var result = {};

    for (var path in table) {
        var cursor = result, length = path.length, property = "", index = 0;

        while (index < length) {
            var char = path.charAt(index);

            if (char === "[") {
                var start = index + 1,
                    end = path.indexOf("]", start),
                    cursor = cursor[property] = cursor[property] || [],
                    property = path.slice(start, end),
                    index = end + 1;
            } else {
                var cursor = cursor[property] = cursor[property] || {},
                    start = char === "." ? index + 1 : index,
                    bracket = path.indexOf("[", start),
                    dot = path.indexOf(".", start);

                if (bracket < 0 && dot < 0) var end = index = length;
                else if (bracket < 0) var end = index = dot;
                else if (dot < 0) var end = index = bracket;
                else var end = index = bracket < dot ? bracket : dot;

                var property = path.slice(start, end);
            }
        }

        cursor[property] = table[path];
    }

    return result[""];
}

퍼포먼스:

  1. 현재 Opera의 솔루션보다 빠릅니다.현재 솔루션은 Opera에서 5% 느립니다.
  2. 파이어폭스의 현재 솔루션보다 느립니다.파이어폭스에서는 솔루션 속도가 26% 느립니다.
  3. 현재 크롬의 솔루션보다 느립니다.내 솔루션은 크롬이 6% 느리다.

JSON 개체를 평탄화 및 평탄화 해제합니다.

전체적으로 현재 솔루션과 동등하게, 또는 더 나은 성능을 발휘합니다.

퍼포먼스:

  1. 현재 Opera의 솔루션보다 빠릅니다.현재 솔루션은 Opera에서 21% 느립니다.
  2. 현재 Firefox 솔루션과 같은 속도입니다.
  3. 파이어폭스의 현재 솔루션보다 빠릅니다.현재 솔루션은 크롬이 20% 느립니다.

출력 형식:

평면 객체는 객체 특성에 점 표기법을 사용하고 배열 색인에 대괄호 표기법을 사용합니다.

  1. {foo:{bar:false}} => {"foo.bar":false}
  2. {a:[{b:["c","d"]}]} => {"a[0].b[0]":"c","a[0].b[1]":"d"}
  3. [1,[2,[3,4],5],6] => {"[0]":1,"[1][0]":2,"[1][1][0]":3,"[1][1][1]":4,"[1][2]":5,"[2]":6}

내 생각에 이 형식은 도트 표기법만 사용하는 것보다 낫다.

  1. {foo:{bar:false}} => {"foo.bar":false}
  2. {a:[{b:["c","d"]}]} => {"a.0.b.0":"c","a.0.b.1":"d"}
  3. [1,[2,[3,4],5],6] => {"0":1,"1.0":2,"1.1.0":3,"1.1.1":4,"1.2":5,"2":6}

장점:

  1. 개체를 평평하게 만드는 것이 현재 솔루션보다 빠릅니다.
  2. 개체의 평탄화 및 평탄화 해제 속도는 현재 솔루션과 같거나 더 빠릅니다.
  3. 평면 객체는 읽기 쉽도록 점 표기법과 괄호 표기법을 모두 사용합니다.

단점:

  1. 대부분의 경우(전부는 아니지만) 현재 솔루션보다 개체의 평탄화 해제 속도가 느립니다.

현재 JSFiddle 데모에서는 다음 값이 출력으로 제공되었습니다.

Nested : 132175 : 63
Flattened : 132175 : 564
Nested : 132175 : 54
Flattened : 132175 : 508

업데이트된 JSFiddle 데모는 다음과 같은 값을 출력으로 제공했습니다.

Nested : 132175 : 59
Flattened : 132175 : 514
Nested : 132175 : 60
Flattened : 132175 : 451

그게 무슨 뜻인지 잘 모르겠으니 jsPerf 결과를 참고하겠습니다.결국 jsPerf는 성능 벤치마킹 유틸리티입니다.JSFiddle은 아니다.

ES6 버전:

const flatten = (obj, path = '') => {        
    if (!(obj instanceof Object)) return {[path.replace(/\.$/g, '')]:obj};

    return Object.keys(obj).reduce((output, key) => {
        return obj instanceof Array ? 
             {...output, ...flatten(obj[key], path +  '[' + key + '].')}:
             {...output, ...flatten(obj[key], path + key + '.')};
    }, {});
}

예:

console.log(flatten({a:[{b:["c","d"]}]}));
console.log(flatten([1,[2,[3,4],5],6]));

3년 반 후...

제 프로젝트에서는 JSON 객체를 mongoDB 도트 표기로 평탄하게 만들고 싶었고 간단한 해결책을 생각해냈습니다.

/**
 * Recursively flattens a JSON object using dot notation.
 *
 * NOTE: input must be an object as described by JSON spec. Arbitrary
 * JS objects (e.g. {a: () => 42}) may result in unexpected output.
 * MOREOVER, it removes keys with empty objects/arrays as value (see
 * examples bellow).
 *
 * @example
 * // returns {a:1, 'b.0.c': 2, 'b.0.d.e': 3, 'b.1': 4}
 * flatten({a: 1, b: [{c: 2, d: {e: 3}}, 4]})
 * // returns {a:1, 'b.0.c': 2, 'b.0.d.e.0': true, 'b.0.d.e.1': false, 'b.0.d.e.2.f': 1}
 * flatten({a: 1, b: [{c: 2, d: {e: [true, false, {f: 1}]}}]})
 * // return {a: 1}
 * flatten({a: 1, b: [], c: {}})
 *
 * @param obj item to be flattened
 * @param {Array.string} [prefix=[]] chain of prefix joined with a dot and prepended to key
 * @param {Object} [current={}] result of flatten during the recursion
 *
 * @see https://docs.mongodb.com/manual/core/document/#dot-notation
 */
function flatten (obj, prefix, current) {
  prefix = prefix || []
  current = current || {}

  // Remember kids, null is also an object!
  if (typeof (obj) === 'object' && obj !== null) {
    Object.keys(obj).forEach(key => {
      this.flatten(obj[key], prefix.concat(key), current)
    })
  } else {
    current[prefix.join('.')] = obj
  }

  return current
}

기능 및/또는 경고

  • JSON 오브젝트만 받아들입니다. 만약에 {a: () => {}}네가 원하는 걸 얻지 못할 수도 있어!
  • 빈 배열 및 개체를 제거합니다. 이 ★★★★★★★★★★★★★★★★★.{a: {}, b: []}{}.

이 라이브러리 사용:

npm install flat

사용방법(https://www.npmjs.com/package/flat):

평탄화:

    var flatten = require('flat')


    flatten({
        key1: {
            keyA: 'valueI'
        },
        key2: {
            keyB: 'valueII'
        },
        key3: { a: { b: { c: 2 } } }
    })

    // {
    //   'key1.keyA': 'valueI',
    //   'key2.keyB': 'valueII',
    //   'key3.a.b.c': 2
    // }

플랫텐 해제:

var unflatten = require('flat').unflatten

unflatten({
    'three.levels.deep': 42,
    'three.levels': {
        nested: true
    }
})

// {
//     three: {
//         levels: {
//             deep: 42,
//             nested: true
//         }
//     }
// }

위의 답변보다 속도가 느리지만(약 1000밀리초), 흥미로운 아이디어를 가진 또 다른 접근방식이 있습니다:-)

각 속성 체인을 통해 반복하는 대신 마지막 속성을 선택하고 나머지는 룩업 테이블을 사용하여 중간 결과를 저장합니다.이 룩업 테이블은 속성 체인이 남아 있지 않고 모든 값이 연결되지 않은 속성에 있을 때까지 반복됩니다.

JSON.unflatten = function(data) {
    "use strict";
    if (Object(data) !== data || Array.isArray(data))
        return data;
    var regex = /\.?([^.\[\]]+)$|\[(\d+)\]$/,
        props = Object.keys(data),
        result, p;
    while(p = props.shift()) {
        var m = regex.exec(p),
            target;
        if (m.index) {
            var rest = p.slice(0, m.index);
            if (!(rest in data)) {
                data[rest] = m[2] ? [] : {};
                props.push(rest);
            }
            target = data[rest];
        } else {
            target = result || (result = (m[2] ? [] : {}));
        }
        target[m[2] || m[1]] = data[p];
    }
    return result;
};

" " " 를 하고 있습니다.data테이블에 대한 입력 매개 변수를 입력하고 테이블에 많은 속성을 추가합니다. 비파괴 버전도 가능합니다. 영리한 사람일지도 모른다lastIndexOf합니다.regex(regex "regex")는 regex(regex "regex")를 사용합니다.

실제 동작은 이쪽에서 확인하세요.

https://github.com/hughsk/flat 를 사용할 수 있습니다.

중첩된 Javascript 개체를 가져와서 평평하게 하거나 구분된 키로 개체의 평활을 해제합니다.

문서의 예

var flatten = require('flat')

flatten({
    key1: {
        keyA: 'valueI'
    },
    key2: {
        keyB: 'valueII'
    },
    key3: { a: { b: { c: 2 } } }
})

// {
//   'key1.keyA': 'valueI',
//   'key2.keyB': 'valueII',
//   'key3.a.b.c': 2
// }


var unflatten = require('flat').unflatten

unflatten({
    'three.levels.deep': 42,
    'three.levels': {
        nested: true
    }
})

// {
//     three: {
//         levels: {
//             deep: 42,
//             nested: true
//         }
//     }
// }

이 코드는 JSON 객체를 반복적으로 평탄화합니다.

코드에 타이밍 메커니즘을 포함시켜 1ms를 주는데 그게 가장 정확한지 모르겠어요.

            var new_json = [{
              "name": "fatima",
              "age": 25,
              "neighbour": {
                "name": "taqi",
                "location": "end of the street",
                "property": {
                  "built in": 1990,
                  "owned": false,
                  "years on market": [1990, 1998, 2002, 2013],
                  "year short listed": [], //means never
                }
              },
              "town": "Mountain View",
              "state": "CA"
            },
            {
              "name": "qianru",
              "age": 20,
              "neighbour": {
                "name": "joe",
                "location": "opposite to the park",
                "property": {
                  "built in": 2011,
                  "owned": true,
                  "years on market": [1996, 2011],
                  "year short listed": [], //means never
                }
              },
              "town": "Pittsburgh",
              "state": "PA"
            }]

            function flatten(json, flattened, str_key) {
                for (var key in json) {
                  if (json.hasOwnProperty(key)) {
                    if (json[key] instanceof Object && json[key] != "") {
                      flatten(json[key], flattened, str_key + "." + key);
                    } else {
                      flattened[str_key + "." + key] = json[key];
                    }
                  }
                }
            }

        var flattened = {};
        console.time('flatten'); 
        flatten(new_json, flattened, "");
        console.timeEnd('flatten');

        for (var key in flattened){
          console.log(key + ": " + flattened[key]);
        }

출력:

flatten: 1ms
.0.name: fatima
.0.age: 25
.0.neighbour.name: taqi
.0.neighbour.location: end of the street
.0.neighbour.property.built in: 1990
.0.neighbour.property.owned: false
.0.neighbour.property.years on market.0: 1990
.0.neighbour.property.years on market.1: 1998
.0.neighbour.property.years on market.2: 2002
.0.neighbour.property.years on market.3: 2013
.0.neighbour.property.year short listed: 
.0.town: Mountain View
.0.state: CA
.1.name: qianru
.1.age: 20
.1.neighbour.name: joe
.1.neighbour.location: opposite to the park
.1.neighbour.property.built in: 2011
.1.neighbour.property.owned: true
.1.neighbour.property.years on market.0: 1996
.1.neighbour.property.years on market.1: 2011
.1.neighbour.property.year short listed: 
.1.town: Pittsburgh
.1.state: PA

제 것은 여기 있어요.Google Apps Script에서 크기가 큰 개체로 2ms 미만으로 실행됩니다.구분자로 점 대신 대시를 사용하여 질문자의 질문처럼 특별히 어레이를 처리하지는 않지만, 이것이 제가 사용하고자 했던 것입니다.

function flatten (obj) {
  var newObj = {};
  for (var key in obj) {
    if (typeof obj[key] === 'object' && obj[key] !== null) {
      var temp = flatten(obj[key])
      for (var key2 in temp) {
        newObj[key+"-"+key2] = temp[key2];
      }
    } else {
      newObj[key] = obj[key];
    }
  }
  return newObj;
}

예:

var test = {
  a: 1,
  b: 2,
  c: {
    c1: 3.1,
    c2: 3.2
  },
  d: 4,
  e: {
    e1: 5.1,
    e2: 5.2,
    e3: {
      e3a: 5.31,
      e3b: 5.32
    },
    e4: 5.4
  },
  f: 6
}

Logger.log("start");
Logger.log(JSON.stringify(flatten(test),null,2));
Logger.log("done");

출력 예:

[17-02-08 13:21:05:245 CST] start
[17-02-08 13:21:05:246 CST] {
  "a": 1,
  "b": 2,
  "c-c1": 3.1,
  "c-c2": 3.2,
  "d": 4,
  "e-e1": 5.1,
  "e-e2": 5.2,
  "e-e3-e3a": 5.31,
  "e-e3-e3b": 5.32,
  "e-e4": 5.4,
  "f": 6
}
[17-02-08 13:21:05:247 CST] done

Object.prototype.flatten = function (obj) {

    let ans = {};
    let anotherObj = { ...obj };
    function performFlatten(anotherObj) {

        Object.keys(anotherObj).forEach((key, idx) => {
            if (typeof anotherObj[key] !== 'object') {
                ans[key] = anotherObj[key];
                console.log('ans so far : ', ans);
            } else {
                console.log(key, { ...anotherObj[key] });
                performFlatten(anotherObj[key]);
            }
        })
    }

    performFlatten(anotherObj);

    return ans;
}

let ans = flatten(obj);
console.log(ans);

선택한 답변에 +/- 10~15%의 효율성을 부가하여 마이너 코드 리팩터링 및 함수 네임스페이스 외부로 재귀 함수를 이동하였습니다.

질문 보기:네임슬레이드 기능은 모든 콜에서 재평가됩니까?네스트된 기능이 느려지는 이유에 대해 설명합니다.

function _flatten (target, obj, path) {
  var i, empty;
  if (obj.constructor === Object) {
    empty = true;
    for (i in obj) {
      empty = false;
      _flatten(target, obj[i], path ? path + '.' + i : i);
    }
    if (empty && path) {
      target[path] = {};
    }
  } 
  else if (obj.constructor === Array) {
    i = obj.length;
    if (i > 0) {
      while (i--) {
        _flatten(target, obj[i], path + '[' + i + ']');
      }
    } else {
      target[path] = [];
    }
  }
  else {
    target[path] = obj;
  }
}

function flatten (data) {
  var result = {};
  _flatten(result, data, null);
  return result;
}

벤치마크를 참조해」를 참조해 주세요.

PowerShell에 정리한 플랫의 재귀적 솔루션은 다음과 같습니다.

#---helper function for ConvertTo-JhcUtilJsonTable
#
function getNodes {
    param (
        [Parameter(Mandatory)]
        [System.Object]
        $job,
        [Parameter(Mandatory)]
        [System.String]
        $path
    )

    $t = $job.GetType()
    $ct = 0
    $h = @{}

    if ($t.Name -eq 'PSCustomObject') {
        foreach ($m in Get-Member -InputObject $job -MemberType NoteProperty) {
            getNodes -job $job.($m.Name) -path ($path + '.' + $m.Name)
        }
        
    }
    elseif ($t.Name -eq 'Object[]') {
        foreach ($o in $job) {
            getNodes -job $o -path ($path + "[$ct]")
            $ct++
        }
    }
    else {
        $h[$path] = $job
        $h
    }
}


#---flattens a JSON document object into a key value table where keys are proper JSON paths corresponding to their value
#
function ConvertTo-JhcUtilJsonTable {
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [System.Object[]]
        $jsonObj
    )

    begin {
        $rootNode = 'root'    
    }
    
    process {
        foreach ($o in $jsonObj) {
            $table = getNodes -job $o -path $rootNode

            # $h = @{}
            $a = @()
            $pat = '^' + $rootNode
            
            foreach ($i in $table) {
                foreach ($k in $i.keys) {
                    # $h[$k -replace $pat, ''] = $i[$k]
                    $a += New-Object -TypeName psobject -Property @{'Key' = $($k -replace $pat, ''); 'Value' = $i[$k]}
                    # $h[$k -replace $pat, ''] = $i[$k]
                }
            }
            # $h
            $a
        }
    }

    end{}
}

예:

'{"name": "John","Address": {"house": "1234", "Street": "Boogie Ave"}, "pets": [{"Type": "Dog", "Age": 4, "Toys": ["rubberBall", "rope"]},{"Type": "Cat", "Age": 7, "Toys": ["catNip"]}]}' | ConvertFrom-Json | ConvertTo-JhcUtilJsonTable
Key              Value
---              -----
.Address.house   1234
.Address.Street  Boogie Ave
.name            John
.pets[0].Age     4
.pets[0].Toys[0] rubberBall
.pets[0].Toys[1] rope
.pets[0].Type    Dog
.pets[1].Age     7
.pets[1].Toys[0] catNip
.pets[1].Type    Cat

저는 json 데이터를 csv 파일로 쉽게 변환할 수 있는 방법을 원했습니다.시나리오에서는 데이터를 어딘가에서 조회하면 은행 추출물 같은 모델의 배열이 수신됩니다.다음의 어프로치는, 이러한 엔트리의 각각을 해석하기 위해서 사용됩니다.

function jsonFlatter(data, previousKey, obj) {
    obj = obj || {}
    previousKey = previousKey || ""
    Object.keys(data).map(key => {
        let newKey = `${previousKey}${previousKey ? "_" : ""}${key}`
        let _value = data[key]
        let isArray = Array.isArray(_value)
        if (typeof _value !== "object" || isArray || _value == null) {
            if (isArray) {
                _value = JSON.stringify(_value)
            } else if (_value == null) {
                _value = "null"
            }
            obj[newKey] = _value
        } else if (typeof _value === "object") {
            if (!Object.keys(_value).length) {
                obj[newKey] = "null"
            } else {
                return jsonFlatter(_value, newKey, obj)
            }
        }
    })
    return obj
}

이렇게 하면 오브젝트 모델의 키와 내부 키의 균일성을 기대할 수 있지만 어레이는 균일성을 신뢰할 수 없기 때문에 스트링화됩니다.또한 빈 객체는 문자열 "null"이 됩니다. 최종 결과에 해당 객체의 키가 나타나기를 원하기 때문입니다.

사용 예:

const test_data = {
    a: {
        aa: {
            aaa: 4354,
            aab: 654
        },
        ab: 123
    },
    b: 234,
    c: {},
    d: []
}

console.log('result', jsonFlatter(test_data)) 

#### output
{
  "a_aa_aaa": 4354,
  "a_aa_aab": 654,
  "a_ab": 123,
  "b": 234,
  "c": "null",
  "d": "[]"
}

이것을 사용해 보세요.

    function getFlattenObject(data, response = {}) {
  for (const key in data) {
    if (typeof data[key] === 'object' && !Array.isArray(data[key])) {
      getFlattenObject(data[key], response);
    } else {
      response[key] = data[key];
    }
  }
  return response;
}

위의 jsFiddler를 사용하는 프로브에 따르면 현재 선택된 것보다 약간 빠른 플랫 케이스의 새로운 버전(이것이 제가 필요했던 것입니다)을 추가하고 싶습니다.게다가 저는 개인적으로 이 스니펫이 좀 더 읽기 쉽다고 생각합니다.이것은 물론 멀티 디벨로퍼 프로젝트에서 중요합니다.

function flattenObject(graph) {
    let result = {},
        item,
        key;

    function recurr(graph, path) {
        if (Array.isArray(graph)) {
            graph.forEach(function (itm, idx) {
                key = path + '[' + idx + ']';
                if (itm && typeof itm === 'object') {
                    recurr(itm, key);
                } else {
                    result[key] = itm;
                }
            });
        } else {
            Reflect.ownKeys(graph).forEach(function (p) {
                key = path + '.' + p;
                item = graph[p];
                if (item && typeof item === 'object') {
                    recurr(item, key);
                } else {
                    result[key] = item;
                }
            });
        }
    }
    recurr(graph, '');

    return result;
}

여기 제가 작업하던 물체를 평평하게 하기 위해 작성한 코드가 있습니다.모든 중첩된 필드를 첫 번째 레이어로 가져오는 새 클래스를 만듭니다.키의 원래 위치를 기억해 두면 이 값을 unflaten으로 변경할 수 있습니다.또한 중첩된 개체 간에 키가 고유하다고 가정합니다.도움이 됐으면 좋겠다.

class JSONFlattener {
    ojson = {}
    flattenedjson = {}

    constructor(original_json) {
        this.ojson = original_json
        this.flattenedjson = {}
        this.flatten()
    }

    flatten() {
        Object.keys(this.ojson).forEach(function(key){
            if (this.ojson[key] == null) {

            } else if (this.ojson[key].constructor == ({}).constructor) {
                this.combine(new JSONFlattener(this.ojson[key]).returnJSON())
            } else {
                this.flattenedjson[key] = this.ojson[key]
            }
        }, this)        
    }

    combine(new_json) {
        //assumes new_json is a flat array
        Object.keys(new_json).forEach(function(key){
            if (!this.flattenedjson.hasOwnProperty(key)) {
                this.flattenedjson[key] = new_json[key]
            } else {
                console.log(key+" is a duplicate key")
            }
        }, this)
    }

    returnJSON() {
        return this.flattenedjson
    }
}

console.log(new JSONFlattener(dad_dictionary).returnJSON())

예를 들어, 이 변환은

nested_json = {
    "a": {
        "b": {
            "c": {
                "d": {
                    "a": 0
                }
            }
        }
    },
    "z": {
        "b":1
    },
    "d": {
        "c": {
            "c": 2
        }
    }
}

안으로

{ a: 0, b: 1, c: 2 }

jpflat 패키지를 사용해 보세요.

확장, 확장, 약속 해결, 어레이 확장, 맞춤형 경로 생성 및 맞춤형 가치 직렬화가 가능합니다.

리듀서 및 시리얼라이저는 전체 경로를 부품의 배열로 받기 때문에 단일 키를 수정하거나 딜리미터를 변경하는 대신 경로에 대해 보다 복잡한 작업을 수행할 수 있습니다.

Json 경로가 기본값입니다. 따라서 "jp" 플랫입니다.

https://www.npmjs.com/package/jpflat

let flatFoo = await require('jpflat').flatten(foo)

언급URL : https://stackoverflow.com/questions/19098797/fastest-way-to-flatten-un-flatten-nested-javascript-objects

반응형