views:

34875

answers:

10

What is most concise/efficient way to find out if a javascript array contains an obj?

This is the only way I know to do it:

contains(a, obj){
  for(var i = 0; i < a.length; i++) {
    if(a[i] === obj){
      return true;
    }
  }
  return false;
}

Is there a better/more concise way to accomplish this?

This is very closely related to this question which addresses finding objects in an array using indexOf.

+1  A: 

If you are using JavaScript 1.6 or later (Firefox 1.5 or later) you can use Array.indexOf. Otherwise, I think you are going to end up with something similar to your original code.

Glomek
+5  A: 

indexOf maybe, but it's a "JavaScript extension to the ECMA-262 standard; as such it may not be present in other implementations of the standard."

Example:

[1, 2, 3].indexOf(1) => 0
["foo", "bar", "baz"].indexOf("bar") => 1
[1, 2, 3].indexOf(4) => -1

AFAICS Microsoft does not offer some kind of alternative to this, but you can add similar functionality to arrays in IE (and other browsers that don't support indexOf) if you want to, as a quick google search reveals (e.g. this one).

cic
actually, there is an example of the an implementation of the indexOf extension for browsers that do not support it on the developer.mozilla.org page you linked to.
Lloyd Cotten
+38  A: 

As others have said, the iteration through the array is probably the best way, but it has been proven that decreasing while loop is the fastest way to iterate in JavaScript. So you may want to rewrite your code as follows:

function contains(a, obj) {
  var i = a.length;
  while (i--) {
    if (a[i] === obj) {
      return true;
    }
  }
  return false;
}

Of course, you may as well extend Array prototype:

Array.prototype.contains = function(obj) {
  var i = this.length;
  while (i--) {
    if (this[i] === obj) {
      return true;
    }
  }
  return false;
}

And now you can simply use the following:

alert([1, 2, 3].contains(2)); // => true
alert([1, 2, 3].contains('2')); // => false
Damir Zekić
But be careful: http://stackoverflow.com/questions/237104/javascript-array-containsobj/1342312#1342312
MatrixFrog
+8  A: 

Here's a Javascript 1.6 compatible implementation of Array.indexOf:

if (!Array.indexOf)
{
  Array.indexOf = [].indexOf ?
      function (arr, obj, from) { return arr.indexOf(obj, from); }:
      function (arr, obj, from) { // (for IE6)
        var l = arr.length,
            i = from ? parseInt( (1*from) + (from<0 ? l:0), 10) : 0;
        i = i<0 ? 0 : i;
        for (; i<l; i++) {
          if (i in arr  &&  arr[i] === obj) { return i; }
        }
        return -1;
      };
}
Már Örlygsson
This looks great, but a little confused:* Aren't the tests on lines 1 and 3 equivalent?* Wouldn't it be better to test the prototype, and add the function to Array.prototype if necessary?
Avi Flax
They aren't equvialent. `[].indexOf` is a shorthand for `Array.prototype.indexOf`. Us paranoid-defensive Javascript programmers avoid extending native prototypes at all cost.
Már Örlygsson
+2  A: 

Extending the javascript Array object is a really bad idea because you introduce new properties (your custom methods) into for-in loops which can break existing scripts. A few years ago the authors of the Prototype library had to re-engineer their library implementation to remove just this kind of thing.

If you don't need to worry about compatibility with other javascript running on your page, go for it, otherwise, I'd recommend the more awkward, but safer free-standing function solution.

Mason Houtz
A: 

Here's how Prototype does it:

/**
 *  Array#indexOf(item[, offset = 0]) -> Number
 *  - item (?): A value that may or may not be in the array.
 *  - offset (Number): The number of initial items to skip before beginning the
 *      search.
 *
 *  Returns the position of the first occurrence of `item` within the array &mdash; or
 *  `-1` if `item` doesn't exist in the array.
**/
function indexOf(item, i) {
  i || (i = 0);
  var length = this.length;
  if (i < 0) i = length + i;
  for (; i < length; i++)
    if (this[i] === item) return i;
  return -1;
}

Also see here for how they hook it up.

Ken
+77  A: 

jQuery has a utility function for this:

$.inArray(value, array)

Returns index of value in array. Returns -1 if array does not contain value.

jQuery has several useful utility functions.

An excellent javascript utility library is underscore.js (indexOf).

Some other frameworks:

  • dojo: dojo.indexOf(array, value, [fromIndex, findLast]) docs. Dojo has a lot of utility functions, see http://api.dojotoolkit.org (scroll down to Functions).
  • prototype: array.indexOf(value) docs
  • mootools: array.indexOf(value) docs
  • mochikit: findValue(array, value) docs
  • MS Ajax: array.indexOf(value) docs

Notice how some frameworks implement this as a function. While other frameworks add the function to the array prototype.

codeape
MooTools also has Array.contains that returns a boolean, which sounds like the real question here.
rpflo
prototype also has `Array.include` that returns a boolean
If you are using a good browser, you can just use `array.indexOf(object) != -1`
Sam Soffes
+1  A: 

Thinking out of the box for a second, if you are in making this call many many times, it is more efficient to use an associative array to do lookups using a hash function.

MattMcKnight
A: 

Just another option

// usage: if ( ['a','b','c','d'].contains('b') ) { ... }
Array.prototype.contains = function(value){
    for (var key in this)
        if (this[key] === value) return true;
    return false;
}
Dennis Allen
But be careful: http://stackoverflow.com/questions/237104/javascript-array-containsobj/1342312#1342312
MatrixFrog