7

I have a json object, say box = {}; to which I will keep adding key-values like box['somename'] = somevalue. There may be repetitions of somename and I want the last instance's value to win. All this is fine.

Now I need to operate on it, as if it were an array. Basically, now that I have a set of unique keys, I want one main operation box.length to see how many unique elements there are. Is there an elegant constant time way of doing it without iterating through all properties of this object?

Sanjeev Satheesh
  • 304
  • 4
  • 16
  • 1
    possible duplicate of [How to efficiently count the number of keys/properties of an object in JavaScript?](http://stackoverflow.com/questions/126100/how-to-efficiently-count-the-number-of-keys-properties-of-an-object-in-javascript) – Lightness Races in Orbit Mar 02 '11 at 19:27
  • yes, looks like that, but the answers here are much better, don't you think :) – Sanjeev Satheesh Mar 02 '11 at 19:41

2 Answers2

9
var box = { 
  length: 0,
  add: function(k, v) {
    if (typeof this[k] === 'undefined')
      this.length++;
    this[k] = v;
  }
}
Eric Mickelsen
  • 9,511
  • 2
  • 27
  • 41
4

Increment a counter every time you add a new element to box.

function Box() {
    var length = 0;
    var items = {};
    this.add = function(k, v) {
        if (!(k in items))
            length++; // don't count twice
        items[k] = v;
    }
    this.get = function(k) {
        return items[k];
    }
    this.delete = function(k) {
        if (k in items)
            length--; 
        delete items[k];
    }
    this.__defineGetter__("length", function() { 
        return length; 
    });
}

This version correctly handles adding and removing elements with any name and provides read-only access to the length property. Usage:

var box = new Box();
box.add("a", 1);
box.add("a", 2); // overwrite
box.add("b", "whatever");
box.add(null, 3);
box.add(undefined, 3);
box.add(undefined, 42);
box.add("", 41);
console.log(box.length); // 5
console.log(box.get(undefined)); // 42 
console.log(box.get(null)); // 3 
console.log(box.get("")); // 41
box.delete(undefined); 
box.delete(undefined); 
box.delete(undefined); 
box.delete(undefined); 
box.delete(undefined); 
box.delete(undefined); 
box.delete(22); // never was defined
console.log(box.length); // 4
console.log(box.get(undefined)); // undefined 
box.add("length", "33") 
box.add("items", "jfhsdjkfh"); 
box.add("length", 77);
console.log(box.length); // 6
Wayne
  • 56,476
  • 13
  • 125
  • 118
  • @Eric - Fixed, but I like your solution better anyway. Much more JavaScripty. – Wayne Mar 02 '11 at 19:37
  • Probably nit-picking, but yours is a more robust approach, since the value itself can be `undefined`. Calling `box.addItem("a", undefined)` multiple times will not increment the `length`. +1 – Anurag Mar 02 '11 at 20:21