Case
Case

Reputation: 4272

If value is in Object javascript

Without using a for is there a way to determine if an object has a value.

var obj = {1: 'j', 54: 1, 29018: 4};

I am looking for something like.

obj.indexOf('j');

I do not really care what the index is just if it's in the object without having nested items.

I am aware I could do, but I am looking for another solution. As this one is really no better than a for.

var array = $.map(obj, function(value, index) {
    return [value];
});
array.indexOf('j');

Upvotes: 1

Views: 110

Answers (3)

Michael Geary
Michael Geary

Reputation: 28850

Every possible solution for this problem will involve a for loop or equivalent. Even if you use a jQuery function as in one of the examples in your question, or if you use a built-in JavaScript function as in some of the answers, there will be a for loop down inside the implementation of those functions.

This is because of the way JavaScript engines represent objects. They typically use a hash table or equivalent, where the object's property names are the keys into the hash table.

This allows fast lookup of property names without iterating over all the object's properties. But there's no hash table going the other way, where the property values are the keys. The only way to find out if a particular value exists in an object is to loop over all the properties - whether you do that yourself with a for loop, or whether you call a library function that hides the for loop.

Of course, it's a great idea to hide that for loop so you don't have to write it out every time. That's what the various library functions do for you. Or, we could go back to first principles and write our own function for this:

// Find a value in an object and return the property name that
// contains that value, or null if not found.
function findValue( object, value ) {
    for( var name in object ) {
        if( object.hasOwnProperty( name ) ) {
            if( object[name] === value ) {
                return name;
            }
        }
    }
}

var obj = { a:'abc', d:'def': g:'ghi' };
console.log( findValue( obj, 'def' ) );  // 'd'
console.log( findValue( obj, 'foo' ) );  // null

The point is that no matter what library function or other solution you find for this, somewhere under the hood will be a for loop very much like the one above.

On the other hand, you don't have to run that for loop every time you look up a value! Even if JavaScript engines don't create a reverse index of the the object (where the object values are keys into the internal hash table), you can create one yourself.

Here's a way you could do that in any old browser:

function ReverseIndex( object ) {
    this.index = {};
    for( var name in object ) {
        if( object.hasOwnProperty(name) ) {
            this.index[ object[name] ] = name;
        }
    }
}

ReverseIndex.prototype.find = function( value ) {
    if( this.index.hasOwnProperty(value) ) {
        return this.index[value];
    }
    return null;
};

var obj = { a:'abc', d:'def', g:'ghi' };
var index = new ReverseIndex( obj );
console.log( index.find( 'def' ) );  // 'd'
console.log( index.find( 'foo' ) );  // null

As you can see, there is still a for loop involved here, when the ReverseIndex is first created. But unlike the first solution, the subsequent calls to index.find() do not require any looping. If you will be searching for values inside the object repeatedly, this could be faster than the first solution because it only has to loop over the object once.

You would need a bit more code if additional properties may be added to the object after you create the ReverseIndex - but I'll leave that as an exercise for the reader at the moment.

And also note that this code assumes that the object values are strings (or convert readily to strings). If the object values are other types, this won't work. See Oriol's answer for a very clean way to do this lookup using a set in modern browsers.

Upvotes: 1

Oriol
Oriol

Reputation: 288080

In the future, you might be able to use Object.values to get an array with the values of an object, and [].includes to check if an array includes some item.

Object.values(obj).includes('j');

However, the former is only a proposal, and the later has only been standardized in a draft.

In case you want to check in the same object multiple times, better store the values in a set. Unlike arrays, searches are required to be sublinear on average (constant if implemented using a hash).

var values = new Set(Object.values(obj));
values.has('j'); // true
values.has('z'); // false

Upvotes: 1

madox2
madox2

Reputation: 51841

You can use Object.keys() to loop over object properties and Array.prototype.some() to check if at least one property fulfill condition (ES6 syntax):

Object.keys(obj).some(key => obj[key] === 'j'); // true

ES5 equivalent:

Object.keys(obj).some(function(key) { return obj[key] === 'j' }); 

Upvotes: 3

Related Questions