Programing

객체의 모든 키를 소문자로 바꾸는 가장 좋은 방법 (가장 효율적)은 무엇입니까?

lottogame 2020. 12. 11. 07:40
반응형

객체의 모든 키를 소문자로 바꾸는 가장 좋은 방법 (가장 효율적)은 무엇입니까?


나는 생각해 냈다

function keysToLowerCase (obj) {
  var keys = Object.keys(obj);
  var n = keys.length;
  while (n--) {
    var key = keys[n]; // "cache" it, for less lookups to the array
    if (key !== key.toLowerCase()) { // might already be in its lower case version
        obj[key.toLowerCase()] = obj[key] // swap the value to a new lower case key
        delete obj[key] // delete the old key
    }
  }
  return (obj);
}

하지만 v8이 어떻게 작동하는지 잘 모르겠습니다. 예를 들어 실제로 다른 키를 삭제하거나 참조 만 삭제하고 가비지 수집기가 나중에 나를 물 릴까요?

또한 이러한 테스트를 만들었습니다. 여기에 답변을 추가하여 어떻게 일치하는지 확인할 수 있기를 바랍니다.

편집 1 : 분명히 테스트에 따르면 키가 이미 소문자인지 확인하지 않으면 더 빠르지 만 더 빠르면 이것을 무시하고 새로운 소문자 키를 생성하여 더 많은 혼란을 만들 수 있습니까? 가비지 수집기가 이것에 만족할까요?


내가 생각 하는 가장 빠른 방법 은 새 개체를 만드는 것입니다.

var key, keys = Object.keys(obj);
var n = keys.length;
var newobj={}
while (n--) {
  key = keys[n];
  newobj[key.toLowerCase()] = obj[key];
}

나는 당신에게 확실한 답을 줄 수있는 v8의 현재 내부 작업에 충분히 익숙하지 않습니다. 몇 년 전에 저는 개발자가 객체에 대해 이야기하는 비디오를 보았습니다. IIRC는 참조 만 삭제하고 가비지 수집기가 처리하도록합니다. 하지만 몇 년 전 이었기 때문에 그때와 같더라도 지금은 그럴 필요가 없습니다.

나중에 물 릴까요? 그것은 당신이하는 일에 따라 다르지만 아마 아닐 것입니다. 수명이 짧은 개체를 만드는 것이 매우 일반적이므로 코드가이를 처리하도록 최적화되어 있습니다. 그러나 모든 환경에는 한계가 있으며 어쩌면 당신을 물릴 수도 있습니다. 실제 데이터로 테스트해야합니다.


내가 사용하는 거라고 소호 - Dash.transform을 다음과 같이 :

var lowerObj = _.transform(obj, function (result, val, key) {
    result[key.toLowerCase()] = val;
});

개인적으로 다음을 사용합니다.

let objectKeysToLowerCase = function (origObj) {
    return Object.keys(origObj).reduce(function (newObj, key) {
        let val = origObj[key];
        let newVal = (typeof val === 'object') ? objectKeysToLowerCase(val) : val;
        newObj[key.toLowerCase()] = newVal;
        return newObj;
    }, {});
}

간결하고 중첩 된 객체를 처리하는 것이 반복되며 원본을 수정하는 대신 새 객체를 반환합니다.

제한된 로컬 테스트에서이 함수는 현재 나열된 다른 재귀 솔루션보다 빠릅니다 (한 번 수정 됨). 나는 다른 사람들과 비교하여 벤치마킹하고 싶지만 jsperf가 현재 다운되었습니다 (???).

또한 ES5.1로 작성되었으므로 MDN의 문서에 따르면 FF 4+, Chrome 5+, IE 9.0+, Opera 12+, Safari 5+ (거의 모든 것)에서 작동해야합니다.

승리를위한 Vanilla JS.

나는이 모든 것의 가비지 콜렉션 측면에 대해 너무 걱정하지 않을 것입니다. 이전 객체에 대한 모든 참조가 소멸되면 GC가되지만 객체는 기본적으로 모든 속성을 참조하므로 그렇지 않습니다.

모든 함수, 배열 또는 RegExp는 참조로 "복사"됩니다. 메모리 측면에서, 대부분의 (모든?) 현대 JS 엔진 사용자 문자열 interning 때문에이 프로세스에 의해 문자열조차도 복제되지 않습니다 . 원래 구조를 형성 한 숫자, 부울 및 객체 만 GC로 남겨 두는 것 같습니다.

원본에 동일한 소문자 표현을 가진 여러 속성이있는 경우이 프로세스 (의 모든 구현)는 값을 잃게됩니다. 즉 :

let myObj = { xx: 'There', xX: 'can be', Xx: 'only', XX: 'one!' };
console.log(myObj);
// { xx: 'There', xX: 'can be', Xx: 'only', XX: 'one!' }

let newObj = objectKeysToLowerCase(myObj);
console.log(newObj);
// { xx: 'one!' }

물론 때로는 이것이 정확히 원하는 것입니다.

2018-07-17 업데이트

몇몇 사람들은 원래 함수가 배열에서 잘 작동하지 않는다고 지적했습니다. 확장되고 탄력적 인 버전이 있습니다. 배열을 통해 올바르게 반복되며 초기 값이 배열 또는 단순 값인 경우 작동합니다.

let objectKeysToLowerCase = function (input) {
    if (typeof input !== 'object') return input;
    if (Array.isArray(input)) return input.map(objectKeysToLowerCase);
    return Object.keys(input).reduce(function (newObj, key) {
        let val = input[key];
        let newVal = (typeof val === 'object') ? objectKeysToLowerCase(val) : val;
        newObj[key.toLowerCase()] = newVal;
        return newObj;
    }, {});
};

사용 Object.fromEntries(ES.next)

새로운 Object.fromEntries방법을 사용하는 네이티브 및 불변 솔루션 :


const newObj = Object.fromEntries(
  Object.entries(obj).map(([k, v]) => [k.toLowerCase(), v])
);

해당 기능이 널리 사용 가능해질 때까지 다음 ES.next polyfill을 사용하여 직접 정의 할 수 있습니다.

Object.fromEntries = arr => Object.assign({}, ...Array.from(arr, ([k, v]) => ({[k]: v}) ));

좋은 점은이 방법이의 반대를 수행 Object.entries하므로 이제 객체와 배열 표현 사이를 앞뒤로 이동할 수 있습니다.


loDash / fp 방식, 본질적으로 하나의 라이너로 매우 좋습니다.

import {
mapKeys
} from 'lodash/fp'

export function lowerCaseObjectKeys (value) {
return mapKeys(k => k.toLowerCase(), value)
}

ES6 버전 :

Object.keys(source)
  .reduce((destination, key) => {
    destination[key.toLowerCase()] = source[key];
    return destination;
  }, {});

forEach를 사용하는 것이 내 테스트에서 조금 더 빠른 것 같습니다. 원래 참조가 사라 졌으므로 새 참조를 삭제하면 gc에 도달합니다.

function keysToLowerCase(obj){
    Object.keys(obj).forEach(function (key) {
        var k = key.toLowerCase();

        if (k !== key) {
            obj[k] = obj[key];
            delete obj[key];
        }
    });
    return (obj);
}

var O = {ONE : 1, two : 2, tHree : 3, FOUR : 4, Five : 5, SIX : {a : 1, b : 2, c : 3, D : 4, E : 5}}; keysToLowerCase (O);

/ * 반환 된 값 : (Object) * /

{
    five:5,
    four:4,
    one:1,
    six:{
        a:1,
        b:2,
        c:3,
        D:4,
        E:5
    },
    three:3,
    two:2
}

단순화 된 답변

간단한 상황에서 다음 예제를 사용하여 모든 키를 소문자로 변환 할 수 있습니다.

Object.keys(example).forEach(key => {
  const value = example[key];
  delete example[key];
  example[key.toLowerCase()] = value;
});

toUpperCase()대신 다음을 사용하여 모든 키를 대문자로 변환 할 수 있습니다 toLowerCase().

Object.keys(example).forEach(key => {
  const value = example[key];
  delete example[key];
  example[key.toUpperCase()] = value;
});

ES6와 TypeScript를 사용했습니다. toLowerCaseObject함수는 배열을 매개 변수로 사용하고 객체 트리를 재귀 적으로 살펴보고 모든 노드를 소문자로 만듭니다.

function toLowerCaseObject(items: any[]) {
        return items.map(x => {
            let lowerCasedObject = {}
                for (let i in x) {
                    if (x.hasOwnProperty(i)) {
                        lowerCased[i.toLowerCase()] = x[i] instanceof Array ? toLowerCaseObject(x[i]) : x[i];
                    }
            }
            return lowerCasedObject;
        });
    }

case를 한 번만 낮추고 lowKeyvar에 저장하는 것을 고려하십시오 .

function keysToLowerCase (obj) {
  var keys = Object.keys(obj);
  var n = keys.length;
  var lowKey;
  while (n--) {
    var key = keys[n];
    if (key === (lowKey = key.toLowerCase()))
    continue

    obj[lowKey] = obj[key]
    delete obj[key]

  }
  return (obj);
}

위의 예 중 하나를 기반으로 한 재귀 버전은 다음과 같습니다.

//updated function
var lowerObjKeys = function(obj) {
  Object.keys(obj).forEach(function(key) {
    var k = key.toLowerCase();
    if (k != key) {
      var v = obj[key]
      obj[k] = v;
      delete obj[key];

      if (typeof v == 'object') {
        lowerObjKeys(v);
      }
    }
  });

  return obj;
}

//plumbing
console = {
  _createConsole: function() {
    var pre = document.createElement('pre');
    pre.setAttribute('id', 'console');
    document.body.insertBefore(pre, document.body.firstChild);
    return pre;
  },
  info: function(message) {
    var pre = document.getElementById("console") || console._createConsole();
    pre.textContent += ['>', message, '\n'].join(' ');
  }
};

//test case
console.info(JSON.stringify(lowerObjKeys({
  "StackOverflow": "blah",
  "Test": {
    "LULZ": "MEH"
  }
}), true));

순환 참조를 추적하지 않으므로 무한 루프가 발생하여 스택 오버플로가 발생할 수 있습니다.


이것은 가장 깨끗한 방법은 아니지만 우리 팀에 효과가 있으므로 공유 할 가치가 있습니다.

백엔드가 대소 문자를 구분하지 않는 언어를 실행하고 데이터베이스와 백엔드가 다른 주요 사례를 생성하므로이 방법을 만들었습니다. 우리에게는 완벽하게 작동했습니다. 날짜는 문자열로 보내고 함수는 보내지 않습니다.

We have reduced it to this one line.

const toLowerCase = (data) => JSON.parse(JSON.stringify(data).replace(/"([^"]+)":/g, ($0, key) => '"' + key.toString().toLowerCase() + '":'))

We clone the object by using the JSON.parse(JSON.stringify(obj)) method. This produces a string version of the object in the JSON format. While the object is in the string form you can use regex as JSON is a predictable format to convert all keys.

Broken up it looks like this.

const toLowerCase = function (data) {
  return JSON.parse(JSON.stringify(data)
   .replace(/"([^"]+)":/g, ($0, key) => {
     return '"' + key.toString().toLowerCase() + '":'
   }))
}

For all values:

to_lower_case = function(obj) {
    for (var k in obj){
        if (typeof obj[k] == "object" && obj[k] !== null)
            to_lower_case(obj[k]);
        else if(typeof obj[k] == "string") {
            obj[k] = obj[k].toLowerCase();
        }
    }
    return obj;
}

Same can be used for keys with minor tweaks.


This is how I do it. My input can be anything and it recuses through nested objects as well as arrays of objects.

const fixKeys = input => Array.isArray(input)
  ? input.map(fixKeys)
  : typeof input === 'object'
  ? Object.keys(input).reduce((acc, elem) => {
      acc[elem.toLowerCase()] = fixKeys(input[elem])
      return acc
    }, {})
  : input

tested using mocha

const { expect } = require('chai')

const fixKeys = require('../../../src/utils/fixKeys')

describe('utils/fixKeys', () => {
  const original = {
    Some: 'data',
    With: {
      Nested: 'data'
    },
    And: [
      'an',
      'array',
      'of',
      'strings'
    ],
    AsWellAs: [
      { An: 'array of objects' }
    ]
  }

  const expected = {
    some: 'data',
    with: {
      nested: 'data'
    },
    and: [
      'an',
      'array',
      'of',
      'strings'
    ],
    aswellas: [{ an: 'array of objects' }]
  }

  let result

  before(() => {
    result = fixKeys(original)
  })

  it('left the original untouched', () => {
    expect(original).not.to.deep.equal(expected)
  })

  it('fixed the keys', () => {
    expect(result).to.deep.equal(expected)
  })
})

var aa = {ID:1,NAME:'Guvaliour'};
var bb= {};
var cc = Object.keys(aa);
cc.forEach(element=>{
 bb[element.toLowerCase()]=aa[element];
});
cosole.log(bb)

참고URL : https://stackoverflow.com/questions/12539574/whats-the-best-way-most-efficient-to-turn-all-the-keys-of-an-object-to-lower

반응형