La mejor manera de encontrar si un elemento está en una matriz de JavaScript? [duplicar]


Esta pregunta ya tiene una respuesta aquí:

¿Cuál es la mejor manera de encontrar si un objeto está en una matriz?

Esta es la mejor manera que conozco:

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
Author: Michał Perłakowski, 2008-09-27

8 answers

A partir de ECMAScript 2016 puede utilizar includes()

arr.includes(obj);

Si desea admitir IE u otros navegadores antiguos:

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

EDITAR: Esto no funcionará en IE6, 7 u 8 sin embargo. La mejor solución es definirlo usted mismo si no está presente:

  1. Mozilla (ECMA-262) versión:

      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. Daniel James ' s version:

    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. Versión de Roosteronacid :

    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);
      }
    );
    
 655
Author: Vinko Vrsalovic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-16 09:37:57

Si está utilizando jQuery:

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

Para más información: http://api.jquery.com/jQuery.inArray /

 202
Author: GerManson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-23 04:28:24

Primero, implemente indexOf en JavaScript para navegadores que aún no lo tengan. Por ejemplo, verarray extras de Erik Arvidsson (también, la entrada de blogasociada ). Y luego puede usar indexOf sin preocuparse por el soporte del navegador. Aquí hay una versión ligeramente optimizada de su implementación 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;
    };
}

Se ha cambiado para almacenar la longitud para que no tenga que buscarla en cada iteración. Pero la diferencia no es enorme. Una función de propósito menos general podría ser más rápido:

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

Prefiero usar la función estándar y dejar este tipo de microoptimización para cuando sea realmente necesario. Pero si estás interesado en la microoptimización, adapté los benchmarks a los que roosterononacid enlazó en los comentarios, a benchmark buscando en arrays. Sin embargo, son bastante crudos, una investigación completa probaría matrices con diferentes tipos, diferentes longitudes y encontraría objetos que ocurren en diferentes lugares.

 32
Author: Daniel James,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-26 15:21:04

Si la matriz no está ordenada, no hay realmente una mejor manera (aparte de usar el indexOf mencionado anteriormente, que creo que equivale a lo mismo). Si la matriz está ordenada, puede hacer una búsqueda binaria, que funciona así:

  1. Elige el elemento central de la matriz.
  2. ¿El elemento que estás buscando es más grande que el elemento que elegiste? Si es así, ha eliminado la mitad inferior de la matriz. Si no lo es, has eliminado la mitad superior.
  3. Elige el medio elemento de la mitad restante de la matriz, y continuar como en el paso 2, eliminando mitades de la matriz restante. Eventualmente encontrará su elemento o no tendrá ninguna matriz para mirar a través.

La búsqueda binaria se ejecuta en tiempo proporcional al logaritmo de la longitud de la matriz, por lo que puede ser mucho más rápida que mirar cada elemento individual.

 10
Author: assortedslog,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-27 16:00:52

Suponiendo que .indexOf() se implementa

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

!!! no haga Array.prototype.has=function(){... porque agregará un elemento enumerable en cada matriz y js está roto.

//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

El uso de 2nd arg (flag) fuerza la comparación por valor en lugar de referencia

 9
Author: bortunac,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-20 02:29:11

Depende de tu propósito. Si programa para la Web, evite indexOf, no es compatible con Internet Explorer 6 (muchos de ellos todavía se utilizan!), o hacer uso condicional:

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

indexOf probablemente está codificado en código nativo, por lo que es más rápido que cualquier cosa que pueda hacer en JavaScript (excepto la búsqueda binaria/dicotomía si el array es apropiado). Nota: es una cuestión de gusto, pero yo haría un return false; al final de su rutina, para devolver un verdadero booleano...

 5
Author: PhiLho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-11 23:55:56

Aquí tienes algunos meta-conocimientos para ti - si quieres saber qué puedes hacer con un Array, revisa la documentación-aquí está la página de Array para Mozilla

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

Allí verás la referencia a indexOf, añadida en Javascript 1.6

 4
Author: Paul Dixon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-02 02:16:48

Una forma robusta de comprobar si un objeto es una matriz en javascript se detalla aquí:

Aquí hay dos funciones de la xa.js framework que adjunto a un utils = {} 'container'. Estos deberían ayudarle a detectar correctamente los arrays.

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

Si luego desea verificar si un objeto está en una matriz, también incluiría este código:

/**
 * 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];
    };
}

Y finalmente esta función 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;
}
 3
Author: Aaria Carter-Weir,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-22 07:47:31