ChatGPT解决这个技术问题 Extra ChatGPT

Determine whether an array contains a value [duplicate]

This question already has answers here: How do I check if an array includes a value in JavaScript? (57 answers) Closed 6 years ago.

I need to determine if a value exists in an array.

I am using the following function:

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

The above function always returns false.

The array values and the function call is as below:

arrValues = ["Sam","Great", "Sample", "High"]
alert(arrValues.contains("Sam"));
The code works in Safari 4.0.2. BTW: I'd do a === comparison instead of just ==.
"The above function always returns false." No it doesn't: The function works as expected - the error must be somewhere else.
Finally its worked. its due to improper trim of the comparing value. there was some space in the comparing value (A comment from the asker, to the accepted answer.)
It works, you should have used === instead of ==

C
Community

jQuery has a utility function for this:

$.inArray(value, array)

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

See also How do I check if an array includes an object in JavaScript?


Don't let the name "inArray" fool you. As mentioned above (but of course I didn't read closely enough), returns -1 (not false) if the element doesn't exist.
@Steve Paul what is wrong with name? it does what it says: -1=it's NOT there, anything else= it's there
'inArray' implies that a boolean will be returned indicating whether the element could be found in the array. Therefore users may feel tempted to use the expression: if ($.inArray('myval', myarray)) {...} This will evaluate to true if 'myval' is NOT in myarray. Furthermore, it will evaluate to false if myval's index is 0.
The non-booleanness of $.inArray's return definitely feels like a mistake on jQuery's part. Surely, it ought to be renamed to $.indexOf, if that's the function it's polyfilling?
It's very easy to suggest that someone uses a JQuery method for everything javascript, but as the original question was for a javascript solution, then one should be provided in that manner
e
eyelidlessness
var contains = function(needle) {
    // Per spec, the way to identify NaN is that it is not equal to itself
    var findNaN = needle !== needle;
    var indexOf;

    if(!findNaN && typeof Array.prototype.indexOf === 'function') {
        indexOf = Array.prototype.indexOf;
    } else {
        indexOf = function(needle) {
            var i = -1, index = -1;

            for(i = 0; i < this.length; i++) {
                var item = this[i];

                if((findNaN && item !== item) || item === needle) {
                    index = i;
                    break;
                }
            }

            return index;
        };
    }

    return indexOf.call(this, needle) > -1;
};

You can use it like this:

var myArray = [0,1,2],
    needle = 1,
    index = contains.call(myArray, needle); // true

CodePen validation/usage


Note that indexOf on arrays is not implemented in IE, but you can define it yourself
you should use a typed comparison with === to be compatible with the native implementation
fixed the comparison and added the missing return -1; please note that according to the ES5 spec, this method will behave differently from the native one in case ofsigned zeroes and NaNs (see 15.4.4.14 and 9.12 vs. 11.9.6)
What version of IE does this answer refer to?
Note that in Sharepoint 2010, WebParts can break if you implement an Array.Prototype: labs.steveottenad.com/type-mismatch-on-wpadder-js
C
Carlos

This is generally what the indexOf() method is for. You would say:

return arrValues.indexOf('Sam') > -1

indexOf does not work in <IE9.
Does not work with NaN
I like how Kenneth J's comment has more upvotes than the answer. But good stuff - I've used indexOf() for strings, but I didn't know you could use it for arrays in general.
return ~arrValues.indexOf('Sam') will return false if element does not exist in array
@SebastianMach and if all web devs just took a stand saying no... users will be forced to change. and helps companies save money since they don't have to hire IE developers
D
Dale

Array.prototype.includes()

In ES2016, there is Array.prototype.includes().

The includes() method determines whether an array includes a certain element, returning true or false as appropriate.

Example

["Sam", "Great", "Sample", "High"].includes("Sam"); // true

Support

According to kangax and MDN, the following platforms are supported:

Chrome 47

Edge 14

Firefox 43

Opera 34

Safari 9

Node 6

Support can be expanded using Babel (using babel-polyfill) or core-js. MDN also provides a polyfill:

if (![].includes) {
  Array.prototype.includes = function(searchElement /*, fromIndex*/ ) {
    'use strict';
    var O = Object(this);
    var len = parseInt(O.length) || 0;
    if (len === 0) {
      return false;
    }
    var n = parseInt(arguments[1]) || 0;
    var k;
    if (n >= 0) {
      k = n;
    } else {
      k = len + n;
      if (k < 0) {k = 0;}
    }
    var currentElement;
    while (k < len) {
      currentElement = O[k];
      if (searchElement === currentElement ||
         (searchElement !== searchElement && currentElement !== currentElement)) {
        return true;
      }
      k++;
    }
    return false;
  };
}

I'm tempted to post this answer across several javascript questions concerning multiple variable values or arrays. The polyfill from MDN is nice.
thanks for this! Babel polyfils it nicely :-) I remember 2 years ago jQuery was in any project and nowadays it's Babel :) big win for JavaScript community! There's table of what's available of ES7 already on many platforms including babel pollyfils kangax.github.io/compat-table/es2016plus
R
Ryan McGeary

It's almost always safer to use a library like lodash simply because of all the issues with cross-browser compatibilities and efficiency.

Efficiency because you can be guaranteed that at any given time, a hugely popular library like underscore will have the most efficient method of accomplishing a utility function like this.

_.includes([1, 2, 3], 3); // returns true

If you're concerned about the bulk that's being added to your application by including the whole library, know that you can include functionality separately:

var includes = require('lodash/collections/includes');

NOTICE: With older versions of lodash, this was _.contains() rather than _.includes().


@threed, you don't have to include the whole library. Partial functionality can be included with require('lodash/collections/contains').
FYI: With lodash 4 it's now _.includes() instead of _.contains().
helper libraries may seem convenient but tend to change (too) often, see comment above "lodash 4 '.contains()' is now '.includes()'"
@anneb that could be said about any library. that's why you have semver and dependency management.
In Lodash versions prior to 2.x _.include() is an alias for _.contains() and there is no _.includes() defined. As of ver. 3.x, _.include() and _.contains() are both aliases for _includes(). But as of ver. 4.x, there is only _.includes() and no more other aliases.
k
kuujinbo

Since ECMAScript6, one can use Set:

var myArray = ['A', 'B', 'C'];
var mySet = new Set(myArray);
var hasB = mySet.has('B'); // true
var hasZ = mySet.has('Z'); // false

nice way to use actually set.
T
Trevor

tl;dr

function includes(k) {
  for(var i=0; i < this.length; i++){
    if( this[i] === k || ( this[i] !== this[i] && k !== k ) ){
      return true;
    }
  }
  return false;
}

Example

function includes(k) { for(var i=0; i < this.length; i++){ if( this[i] === k || ( this[i] !== this[i] && k !== k ) ){ return true; } } return false; } function log(msg){ $('#out').append('

' + msg + '
'); } var arr = [1, "2", NaN, true]; arr.includes = includes; log('var arr = [1, "2", NaN, true];'); log('
'); log('arr.includes(1): ' + arr.includes(1)); log('arr.includes(2): ' + arr.includes(2)); log('arr.includes("2"): ' + arr.includes("2")); log('arr.includes(NaN): ' + arr.includes(NaN)); log('arr.includes(true): ' + arr.includes(true)); log('arr.includes(false): ' + arr.includes(false)); #out{ font-family:monospace; }

Longer Answer

I know this question isn't really about whether or not to extend built-in objects, but the attempt of the OP and the comments on this answer highlight that debate. My comment from Feb 12, '13 cites an article that outlines this debate really well, however that link broke and I can't edit the original comment because too much time has passed, so I include it here.

If you're looking to extend the built-in Array object with a contains method, probably the best and most responsible way to do this would be to use this polyfill from MDN. (See also this section of the MDN article on Prototypical inheritance, which explains that "The only good reason for extending a built-in prototype is to backport the features of newer JavaScript engines; for example Array.forEach, etc.")

if (!Array.prototype.includes) {
  Array.prototype.includes = function(searchElement /*, fromIndex*/ ) {
    'use strict';
    var O = Object(this);
    var len = parseInt(O.length) || 0;
    if (len === 0) {
      return false;
    }
    var n = parseInt(arguments[1]) || 0;
    var k;
    if (n >= 0) {
      k = n;
    } else {
      k = len + n;
      if (k < 0) {k = 0;}
    }
    var currentElement;
    while (k < len) {
      currentElement = O[k];
      if (searchElement === currentElement ||
         (searchElement !== searchElement && currentElement !== currentElement)) {
        return true;
      }
      k++;
    }
    return false;
  };
}

Don't want strict equality, or want to choose?

function includes(k, strict) {
  strict = strict !== false; // default is true
  // strict = !!strict; // default is false
  for(var i=0; i < this.length; i++){
    if( (this[i] === k && strict) || 
        (this[i] == k && !strict) ||
        (this[i] !== this[i] && k !== k)
    ) {
      return true;
    }
  }
  return false;
}

Isn't this technique of augmenting built-in types frowned upon?
Buggy: [1,2,4].contains([].contains) is true. Also unnecessarily slow due to the same bug. Avoid for..in over arrays.
@Eamon Nerbonne: I just pasted that code into jsfiddle.net and got false. Am I doing something wrong. Also, could you elaborate on how this bug slows the code down? Finally, I wasn't aware that there is a performance difference for "for..in" loops. Could you explain or direct me towards an article where I could read more?
@threed totally untrue: "This is a very common practice and is used extensively by jQuery" - they create new prototypes for some objects they use, but NOT modify built-in prototypes
M
Matías Cánepa

My little contribution:

function isInArray(array, search)
{
    return array.indexOf(search) >= 0;
}

//usage
if(isInArray(my_array, "my_value"))
{
    //...
}

S
SoEzPz

If you have access to ECMA 5 you can use the some method.

MDN SOME Method Link

arrValues = ["Sam","Great", "Sample", "High"];

function namePresent(name){
  return name === this.toString();
}
// Note:
// namePresent requires .toString() method to coerce primitive value
// i.e. String {0: "S", 1: "a", 2: "m", length: 3, [[PrimitiveValue]]: "Sam"}
// into
// "Sam"

arrValues.some(namePresent, 'Sam');
=> true;

If you have access to ECMA 6 you can use the includes method.

MDN INCLUDES Method Link

arrValues = ["Sam","Great", "Sample", "High"];

arrValues.includes('Sam');
=> true;

r
rlovtang

Given the implementation of indexOf for IE (as described by eyelidlessness):

Array.prototype.contains = function(obj) {
    return this.indexOf(obj) > -1;
};

That's redundant.
Maybe, but it makes your code cleaner. if (myArray.contains(obj)) is easier to read and states the intent better than if (myArray.indexOf(obj) > -1). I definitively would implement both.
Does this work in all browsers? Or do some browsers consider the index of "2" and 2 the same?
W
Wojciech Bednarski

You can use _.indexOf method or if you don't want to include whole Underscore.js library in your app, you can have a look how they did it and extract necessary code.

    _.indexOf = function(array, item, isSorted) {
    if (array == null) return -1;
    var i = 0, l = array.length;
    if (isSorted) {
      if (typeof isSorted == 'number') {
        i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted);
      } else {
        i = _.sortedIndex(array, item);
        return array[i] === item ? i : -1;
      }
    }
    if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
    for (; i < l; i++) if (array[i] === item) return i;
    return -1;
  };

H
Hunan Rostomyan

Another option would be to use Array.some (if available) in the following way:

Array.prototype.contains = function(obj) {
  return this.some( function(e){ return e === obj } );
}

The anonymous function passed to Array.some will return true if and only if there is an element in the array that is identical to obj. Absent such an element, the function will not return true for any of the elements of the array, so Array.some will return false as well.


C
Chris Schmitz

Wow, there are a lot of great answers to this question.

I didn't see one that takes a reduce approach so I'll add it in:

var searchForValue = 'pig';

var valueIsInArray = ['horse', 'cat', 'dog'].reduce(function(previous, current){
    return previous || searchForValue === current ? true : false;
}, false);

console.log('The value "' + searchForValue + '" is in the array: ' + valueIsInArray);

Here's a fiddle of it in action.


I was actually thinking about going this route, but it still has to transverse the entire array even when a result is found.
@cgatian that's a good point. It's def something to keep in mind when picking which method to use. You could potentially wrap the reduce statement in a try catch block and throw an exception once you've found the value, but if you do that I think you lose some of the simplicity that the functional approach gives you.
K
Kakoroat

The answer provided didn't work for me, but it gave me an idea:

Array.prototype.contains = function(obj)
    {
        return (this.join(',')).indexOf(obj) > -1;
    }

It isn't perfect because items that are the same beyond the groupings could end up matching. Such as my example

var c=[];
var d=[];
function a()
{
    var e = '1';
    var f = '2';
    c[0] = ['1','1'];
    c[1] = ['2','2'];
    c[2] = ['3','3'];
    d[0] = [document.getElementById('g').value,document.getElementById('h').value];

    document.getElementById('i').value = c.join(',');
    document.getElementById('j').value = d.join(',');
    document.getElementById('b').value = c.contains(d);
}

When I call this function with the 'g' and 'h' fields containing 1 and 2 respectively, it still finds it because the resulting string from the join is: 1,1,2,2,3,3

Since it is doubtful in my situation that I will come across this type of situation, I'm using this. I thought I would share incase someone else couldn't make the chosen answer work either.


This solution seems very fragile and prone to error in all but the most narrow cases. Imagine, for example, using this array: var arr = ["Smith, Reed", "Jackson, Frank"]; arr.contains(searchTerm); Image that some user accidentally typed "Reed,Jackson" instead of "Reed, Jackson" in some text field that searched through this array. This algorithm would return a false positive and the user would think that Reed, Jackson actually existed when it doesn't. Cases like this are why this algorithm is much more prone to bugs.
N
Nikhil Vartak

Using array .map function that executes a function for every value in an array seems cleanest to me.

Ref: Array.prototype.map()

This method can work well both for simple arrays and for arrays of objects where you need to see if a key/value exists in an array of objects.

function inArray(myArray,myValue){
    var inArray = false;
    myArray.map(function(key){
        if (key === myValue){
            inArray=true;
        }
    });
    return inArray;
};

var anArray = [2,4,6,8]
console.log(inArray(anArray, 8)); // returns true
console.log(inArray(anArray, 1)); // returns false

function inArrayOfObjects(myArray,myValue,objElement){
    var inArray = false;
    myArray.map(function(arrayObj){
        if (arrayObj[objElement] === myValue) {
            inArray=true;
        }
    });
    return inArray;
};

var objArray = [{id:4,value:'foo'},{id:5,value:'bar'}]
console.log(inArrayOfObjects(objArray, 4, 'id')); // returns true
console.log(inArrayOfObjects(objArray, 'bar', 'value')); // returns true
console.log(inArrayOfObjects(objArray, 1, 'id')); // returns false

c
codefreaK
function setFound(){   
 var l = arr.length, textBox1 = document.getElementById("text1");
    for(var i=0; i<l;i++)
    {
     if(arr[i]==searchele){
      textBox1 .value = "Found";
      return;
     }
    }
    textBox1 .value = "Not Found";
return;
}

This program checks whether the given element is found or not. Id text1 represents id of textbox and searchele represents element to be searched (got fron user); if you want index, use i value


Please give the explanation to your code. Code only answers are not appreciated
This program checks whether the given element is found or not. Id text1 represents id of textbox and searchele represents element to be searched (got fron user); if you want index, use i value.
Please update it in your answer.
J
John Slegers

The simplest solution for a contains function, would be a function that looks like this :

var contains = function (haystack, needle) {
    return !!~haystack.indexOf(needle);
}

Ideally, you wouldn't make this a stand-alone function, though, but part of a helper library :

var helper = {};

helper.array = {
    contains : function (haystack, needle) {
        return !!~haystack.indexOf(needle);
    }, 
    ...
};

Now, if you happen to be one of those unlucky people who still needs to support IE<9 and thus can't rely on indexOf, you could use this polyfill, which I got from the MDN :

if (!Array.prototype.indexOf) {
  Array.prototype.indexOf = function(searchElement, fromIndex) {
    var k;
    if (this == null) {
      throw new TypeError('"this" is null or not defined');
    }
    var o = Object(this);
    var len = o.length >>> 0;
    if (len === 0) {
      return -1;
    }
    var n = +fromIndex || 0;

    if (Math.abs(n) === Infinity) {
      n = 0;
    }
    if (n >= len) {
      return -1;
    }
    k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
    while (k < len) {
      if (k in o && o[k] === searchElement) {
        return k;
      }
      k++;
    }
    return -1;
  };
}

v
valeri

I prefer simplicity:

var days = [1, 2, 3, 4, 5];
if ( 2 in days ) {console.log('weekday');}

He wants to find a value in an array, not an index. So this won't do the job, even if it is simple. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…