Лучший способ найти элемент в массиве JavaScript?
Каков наилучший способ найти объект в массиве?
Это лучший способ, который я знаю:
function include(arr, obj) {
for(var i=0; i<arr.length; i++) {
if (arr[i] == obj) return true;
}
}
include([1,2,3,4], 3); // true
include([1,2,3,4], 6); // undefined
Ответы
Ответ 1
С ECMAScript 2016 вы можете использовать includes()
arr.includes(obj);
Если вы хотите поддерживать IE или другие старые браузеры:
function include(arr,obj) {
return (arr.indexOf(obj) != -1);
}
EDIT: Это не будет работать на IE6, 7 или 8. Лучшее обходное решение - определить его самостоятельно, если оно отсутствует:
-
Версия Mozilla (ECMA-262):
if (!Array.prototype.indexOf)
{
Array.prototype.indexOf = function(searchElement /*, fromIndex */)
{
"use strict";
if (this === void 0 || this === null)
throw new TypeError();
var t = Object(this);
var len = t.length >>> 0;
if (len === 0)
return -1;
var n = 0;
if (arguments.length > 0)
{
n = Number(arguments[1]);
if (n !== n)
n = 0;
else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0))
n = (n > 0 || -1) * Math.floor(Math.abs(n));
}
if (n >= len)
return -1;
var k = n >= 0
? n
: Math.max(len - Math.abs(n), 0);
for (; k < len; k++)
{
if (k in t && t[k] === searchElement)
return k;
}
return -1;
};
}
-
Версия Daniel James:
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (obj, fromIndex) {
if (fromIndex == null) {
fromIndex = 0;
} else if (fromIndex < 0) {
fromIndex = Math.max(0, this.length + fromIndex);
}
for (var i = fromIndex, j = this.length; i < j; i++) {
if (this[i] === obj)
return i;
}
return -1;
};
}
-
роуроновая кислота:
Array.prototype.hasObject = (
!Array.indexOf ? function (o)
{
var l = this.length + 1;
while (l -= 1)
{
if (this[l - 1] === o)
{
return true;
}
}
return false;
} : function (o)
{
return (this.indexOf(o) !== -1);
}
);
Ответ 2
Если вы используете jQuery:
$.inArray(5 + 5, [ "8", "9", "10", 10 + "" ]);
Для получения дополнительной информации: http://api.jquery.com/jQuery.inArray/
Ответ 3
Во-первых, внедрите indexOf
в JavaScript для браузеров, которые еще не имеют его. Например, см. дополнительные атрибуты Erik Arvidsson (также связанный пост в блоге). И тогда вы можете использовать indexOf
, не беспокоясь о поддержке браузера. Здесь немного оптимизированная версия его реализации indexOf
:
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (obj, fromIndex) {
if (fromIndex == null) {
fromIndex = 0;
} else if (fromIndex < 0) {
fromIndex = Math.max(0, this.length + fromIndex);
}
for (var i = fromIndex, j = this.length; i < j; i++) {
if (this[i] === obj)
return i;
}
return -1;
};
}
Он изменился, чтобы сохранить длину, так что ей не нужно искать ее на каждой итерации. Но разница не огромна. Менее универсальная функция может быть быстрее:
var include = Array.prototype.indexOf ?
function(arr, obj) { return arr.indexOf(obj) !== -1; } :
function(arr, obj) {
for(var i = -1, j = arr.length; ++i < j;)
if(arr[i] === obj) return true;
return false;
};
Я предпочитаю использовать стандартную функцию и оставляю такую микро-оптимизацию, когда она действительно нужна. Но если вы увлекаетесь микро-оптимизацией, я адаптировал теги , которые связаны с roosterononacid в комментариях, до сравнительный поиск в массивах. Они довольно грубые, хотя полное расследование будет проверять массивы разных типов, разных длин и нахождение объектов, которые встречаются в разных местах.
Ответ 4
Если массив несортирован, на самом деле нет лучшего способа (кроме использования вышеупомянутого indexOf, который, по моему мнению, является одним и тем же). Если массив отсортирован, вы можете выполнить двоичный поиск, который работает следующим образом:
- Выберите средний элемент массива.
- Элемент, который вы ищете больше, чем тот элемент, который вы выбрали? Если это так, вы устранили нижнюю половину массива. Если это не так, вы устранили верхнюю половину.
- Выберите средний элемент оставшейся половины массива и продолжайте, как на шаге 2, устраняя половинки оставшегося массива. В конце концов вы либо найдете свой элемент, либо не увидите массив, чтобы просмотреть его.
Двоичный поиск выполняется во времени, пропорциональном логарифму длины массива, поэтому он может быть намного быстрее, чем смотреть на каждый отдельный элемент.
Ответ 5
предполагается .indexOf()
Object.defineProperty( Array.prototype,'has',
{
value:function(o, flag){
if (flag === undefined) {
return this.indexOf(o) !== -1;
} else { // only for raw js object
for(var v in this) {
if( JSON.stringify(this[v]) === JSON.stringify(o)) return true;
}
return false;
},
// writable:false,
// enumerable:false
})
!!! не делайте Array.prototype.has=function(){...
, потому что вы добавите перечислимый элемент в каждый массив, а js будет разбит.
//use like
[22 ,'a', {prop:'x'}].has(12) // false
["a","b"].has("a") // true
[1,{a:1}].has({a:1},1) // true
[1,{a:1}].has({a:1}) // false
использование второго аргумента arg (флаг) сравнивает значение по значению вместо ссылки
Ответ 6
Это зависит от вашей цели. Если вы программируете для Интернета, избегайте indexOf
, он не поддерживается Internet Explorer 6 (многие из них все еще используются!) Или выполняются условно:
if (yourArray.indexOf !== undefined) result = yourArray.indexOf(target);
else result = customSlowerSearch(yourArray, target);
indexOf
, вероятно, закодирован в собственном коде, поэтому он быстрее, чем все, что вы можете сделать в JavaScript (кроме бинарного поиска/дихотомии, если массив подходит).
Примечание: это вопрос вкуса, но я бы сделал return false;
в конце вашей подпрограммы, чтобы вернуть истинное логическое...
Ответ 7
Вот некоторые мета-знания для вас - если вы хотите знать, что вы можете делать с массивом, проверьте документацию - здесь страница Массив для Mozilla
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array
Там вы увидите ссылку на indexOf, добавленную в Javascript 1.6
Ответ 8
Здесь подробно описан надежный способ проверить, является ли объект массивом в javascript:
Вот две функции из xa.js рамки, которые я прикрепляю к контейнеру utils = {}
. Они должны помочь вам правильно определить массивы.
var utils = {};
/**
* utils.isArray
*
* Best guess if object is an array.
*/
utils.isArray = function(obj) {
// do an instanceof check first
if (obj instanceof Array) {
return true;
}
// then check for obvious falses
if (typeof obj !== 'object') {
return false;
}
if (utils.type(obj) === 'array') {
return true;
}
return false;
};
/**
* utils.type
*
* Attempt to ascertain actual object type.
*/
utils.type = function(obj) {
if (obj === null || typeof obj === 'undefined') {
return String (obj);
}
return Object.prototype.toString.call(obj)
.replace(/\[object ([a-zA-Z]+)\]/, '$1').toLowerCase();
};
Если вы хотите проверить, находится ли объект в массиве, я бы также включил этот код:
/**
* Adding hasOwnProperty method if needed.
*/
if (typeof Object.prototype.hasOwnProperty !== 'function') {
Object.prototype.hasOwnProperty = function (prop) {
var type = utils.type(this);
type = type.charAt(0).toUpperCase() + type.substr(1);
return this[prop] !== undefined
&& this[prop] !== window[type].prototype[prop];
};
}
И, наконец, эта функция in_array:
function in_array (needle, haystack, strict) {
var key;
if (strict) {
for (key in haystack) {
if (!haystack.hasOwnProperty[key]) continue;
if (haystack[key] === needle) {
return true;
}
}
} else {
for (key in haystack) {
if (!haystack.hasOwnProperty[key]) continue;
if (haystack[key] == needle) {
return true;
}
}
}
return false;
}