Лучший способ определить, находится ли элемент в массиве JavaScript?[дубликат]

StackOverflow https://stackoverflow.com/questions/143847

  •  02-07-2019
  •  | 
  •  

Вопрос

На этот вопрос уже есть ответ здесь:

Каков наилучший способ определить, находится ли объект в массиве?

Это лучший способ, который я знаю:

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
Это было полезно?

Решение

Начиная с ECMAScript 2016, вы можете использовать includes()

arr.includes(obj);

Если вы хотите поддерживать IE или другие старые браузеры:

function include(arr,obj) {
    return (arr.indexOf(obj) != -1);
}

Редактировать:Однако это не будет работать в IE6, 7 или 8.Лучший обходной путь - определить его самостоятельно, если его нет:

  1. Mozilla's версия (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;
      };
    
    }
    
  2. Дэниел Джеймсверсия пользователя:

    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;
      };
    }
    
  3. петушиная кислотаверсия пользователя:

    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);
      }
    );
    

Другие советы

Если вы используете jQuery:

$.inArray(5 + 5, [ "8", "9", "10", 10 + "" ]);

Для получения дополнительной информации: http://api.jquery.com/jQuery .Неразборчивый/

Во-первых, внедрить indexOf в JavaScript для браузеров, в которых его еще нет.Например, смотрите Множество дополнительных услуг Эрика Арвидссона (кроме того, связанная запись в блоге).И тогда вы сможете использовать 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, на который ссылаются в комментариях, к поиск бенчмарков в массивах.Хотя они довольно грубые, полное исследование позволило бы протестировать массивы разных типов, разной длины и найти объекты, которые встречаются в разных местах.

Если массив не отсортирован, на самом деле нет лучшего способа (кроме использования вышеупомянутого indexOf , что, я думаю, равносильно тому же).Если массив отсортирован, вы можете выполнить двоичный поиск, который работает следующим образом:

  1. Выберите средний элемент массива.
  2. Является ли элемент, который вы ищете, больше того, который вы выбрали?Если это так, то вы удалили нижнюю половину массива.Если это не так, то вы исключили верхнюю половину.
  3. Выберите средний элемент оставшейся половины массива и продолжайте, как в шаге 2, исключая половины оставшегося массива.В конце концов вы либо найдете свой элемент, либо у вас не останется массива для просмотра.

Двоичный поиск выполняется за время, пропорциональное логарифму длины массива, поэтому он может быть намного быстрее, чем просмотр каждого отдельного элемента.

[ ].имеет(obj)

предполагая .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

использование 2-го аргумента (флага) приводит к принудительному сравнению по значению вместо ссылки

сравнение необработанных объектов

[o1].has(o2,true) // true if every level value is same

Это зависит от вашей цели.Если вы программируете для Интернета, избегайте indexOf, он не поддерживается Internet Explorer 6 (многие из них все еще используются!), или использовать условно:

if (yourArray.indexOf !== undefined) result = yourArray.indexOf(target);
else result = customSlowerSearch(yourArray, target);

indexOf вероятно, он закодирован в машинном коде, поэтому он быстрее всего, что вы можете сделать в JavaScript (за исключением двоичного поиска / дихотомии, если массив подходит).Примечание:это вопрос вкуса, но я бы сделал return false; в конце вашей процедуры, чтобы вернуть истинное логическое значение...

Вот вам некоторые мета-знания - если вы хотите знать, что вы можете сделать с массивом, ознакомьтесь с документацией - вот страница массива для Mozilla

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array

Там вы увидите ссылку на indexOf, добавленную в Javascript 1.6

Надежный способ проверить, является ли объект массивом в 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;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top