What's the most efficient way to turn an object's keys to its lowercase version

JavaScript performance comparison

Revision 10 of this test case created by some

Info

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

Improved test by testing that it actually do something what it is supposed to do and produces the right result.

The SETUP part is run ONCE for each clocked loop. So if you declare an object there, and then modify it in the tests, it is only the first iteration of the loop that gets the original data. On a test I did the test code was run 22981 times, but only got the right input 120 times. Solved by creating a new object for every test, by calling function getObj.

Another important step is to verify that the data you get back is what you expect. I added the verify function to do that, but after each algorithm is verified it isn't necessary to have the verify code in the benchmark and therefore the call to it is commented out in the tests.

Preparation code

 
<script>
Benchmark.prototype.setup = function() {
    function getObj() {
    return {
      "SomeThing": 2,
      "OthErThing": 9,
      "AnotherThing": 10000,
      "OhAndOneMoreThing": 193013923,
      "aQuiteLargeStringaQuiteLargeStringaQuiteLargeString": 29320381,
      "SomeThing2": 2,
      "OthErThing2": 9,
      "AnotherThing2": 10000,
      "OhAndOneMoreThing2": 193013923,
      "aQuiteLargeStringaQuiteLargeStringaQuiteLargeString2": 29320381,
      "SomeThing3": 2,
      "OthErThing3": 9,
      "AnotherThing3": 10000,
      "OhAndOneMoreThing3": 193013923,
      "aQuiteLargeStringaQuiteLargeStringaQuiteLargeString3": 29320381,
      "SomeThing4": 2,
      "OthErThing4": 9,
      "AnotherThing4": 10000,
      "OhAndOneMoreThing4": 193013923,
      "aQuiteLargeStringaQuiteLargeStringaQuiteLargeString4": 29320381,
      "SomeThing5": 2,
      "OthErThing5": 9,
      "AnotherThing5": 10000,
      "OhAndOneMoreThing5": 193013923,
      "aQuiteLargeStringaQuiteLargeStringaQuiteLargeString5": 29320381
    }
    }
   
    var obj = getObj();
    var objvrfy = Object.keys(obj).reduce(
      function(prev,current,idx,keys){
        prev[current.toLowerCase()] = obj[current];
        return prev;
      },
      {}
    );
    function verify(obj) {
      var vkeys = Object.keys(objvrfy);
      var okeys = Object.keys(obj);
      if (vkeys.length!=okeys.length) {
        throw new Error(
          'Expected ' + vkeys.length + ' keys, '+
          'but got ' + okeys.length
        );
      }
     
      vkeys.every(
        function(key){
          if (objvrfy[key]!==obj[key]) {
            throw new Error(
              'Expected ' + key + ' = "' + escape(objvrfy[key]) + '" '+
              'but got "' +escape(obj[key]) + '"'
            );
          }
          return true;
        }
      );
      return true;
    }
   
    var own = Object.prototype.hasOwnProperty;
   
};
</script>

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
joaojeronimo's function
var obj = getObj();
//if (obj.SomeThing!==2) throw new Error('Illegal input');

var keys = Object.keys(obj);
var n = keys.length;
while (n--) {
  var key = keys[n];
  if (key !== key.toLowerCase()) {
    obj[key.toLowerCase()] = obj[key]
    delete obj[key]
  }
}

//verify(obj);
pending…
Don't check if the key is already in lower case
var obj = getObj();
// Might be cheaper to just change it, but I doubt it
var keys = Object.keys(obj);
var n = keys.length;
while (n--) {
  var key = keys[n];
  obj[key.toLowerCase()] = obj[key]
  delete obj[key]
}
//verify(obj);
pending…
moonwave99
var obj = getObj();
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]

}

//verify(obj);
pending…
var obj = getObj();
var keyLower;
for (var key in obj) {
  keyLower = key.toLowerCase();
  if (keyLower != key) {
    obj[keyLower] = obj[key];
    delete obj[key];
  }
}

//verify(obj);
pending…
kennebec
var obj = getObj();
Object.keys(obj).forEach(
  function(key){
    var k=key.toLowerCase();
    if(k!= key){
      obj[k]= obj[key]
      delete obj[key];
      }
  }
);

//verify(obj);
pending…
some 1
var obj = getObj();
var keys = Object.keys(obj);
var n = keys.length;
var key, lowKey;
while (n--) {
  key = keys[n];
  lowKey = key.toLowerCase();
  if (key != lowKey) { // faster than !==
    obj[lowKey] = obj[key]
    delete obj[key]
  }
}

//verify(obj);
pending…
some 2 (new object)
var obj = getObj();
var keys = Object.keys(obj);
var n = keys.length;
var newobj={}
while (n--) {
  key = keys[n];
  newobj[key.toLowerCase()] = obj[key];
}

//verify(newobj);
pending…
some 3
// inspired by moonwave99

var obj = getObj();
var keys = Object.keys(obj);
var n = keys.length;
var key, lowKey;
while (n--) {
  if ((key=keys[n]) == (lowKey = key.toLowerCase())) continue;
  obj[lowKey] = obj[key]
  delete obj[key];
}
//verify(obj);
pending…
some 4
// inspired by moonwave99

var obj = getObj();
var keys = Object.keys(obj);
var n = keys.length;
var key, lowKey;
while (n--) {
  if ((key=keys[n]) != (lowKey = key.toLowerCase())) {
    obj[lowKey] = obj[key]
    delete obj[key];
  }
}
//verify(obj);
 
pending…

Compare results of other browsers

Revisions

You can edit these tests or add even more tests to this page by appending /edit to the URL. Here’s a list of current revisions for this page:

0 comments

Add a comment