Question

I'm surprised that I can't find an answer to this question on StackOverflow (maybe I'm not searching right).

But basically I'm curious to know if there is something similar to the Array.indexOf() method, but for objects. That is, an efficient method of returning the index(es) of a value within an existing Object.

For example, say I have an object:

var obj = { prop1: "a", prop2: "b", prop3: "c", prop4: "a" };

Now I want to find the index(es) that contain "a", it would be nice to do a obj.indexOf("a") and have it return something like ["prop1", "prop4"]

But this doesn't seem to be an implemented method for objects.

Alternatively, I know I can create a function:

function indexOf(val, obj){
  var indexes = [];

  for (var index in obj){
      if(!obj.hasOwnProperty(index)) continue;

      if(obj[index] == val){
        indexes.push(index);
      }   
   }

   if(!indexes.length) return false;
   else return indexes;
}

indexOf("a", obj); // returns ["prop1","prop4"]

But this kind of feels clunky to iterate over the whole object this way!! Some of the objects I'll be dealing with will be quite huge and the values might be quite large as well.

Is there a better, more efficient way?

Était-ce utile?

La solution

If you have a really huge object, you could use a nice weakmap implementation with the complexity of O(1) to store keys per single object. Therefor you have to implement your hash collection, so when setting a key-value pair, you also store the key in the weakmap. I made also some bench. comparison of this custom HashMap vs RawObject search - jsperf

function HashMap() {
    this.__map = new WeakMap;
    this.__hash = {};
}

HashMap.prototype = {
    set: function(key, value){
        this.unset(key);

        if (value == null) 
            return;

        this.__hash[key] = value;

        var keys = this.__map.get(value);
        if (keys == null) 
            this.__map.set(value, keys = []);

        keys.push(key);
    },
    unset: function(key){
        var value = this.__hash[key];
        if (value) {

            var keys = this.__map.get(value),
                index = keys.indexOf(key);

            keys.splice(index, 1);
        }
        this.__hash[key] = void 0;
    },

    get: function(key){
        return this.__hash[key];
    },
    getKeys: function(value){
        return this.__map.get(value);
    }
};

WeakMap uses Object.defineProperty method in its core. For this reason there are some limitations:

  • browsers: IE9+
  • Objects as Values in above HashMap example, because they are used as Keys in WeakMap Collection

But this approach makes a huge performance boost, as there is no need to iterate over the object, to look for a specific value.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top