2008-09-27 19 views
669

¿Cuál es la mejor manera de encontrar si un objeto está en una matriz?¿La mejor manera de encontrar si un artículo está en una matriz de JavaScript?

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 
+0

Ver: http://stackoverflow.com/a/25765186/1320932 –

+3

2 cosas: 1.) 'incluye' es un nombre realmente malo para una función que no modifica el estado de nada. Es especialmente malo para una función que simplemente devuelve un valor booleano. 2.) Debe agregar "return (false);" antes del final de la función. – Aquarelle

+1

a partir de ECMAScript 2016, puede utilizar la función Array.prototype.includes: myArray.includes (3); // true – mhd

Respuesta

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

EDIT: Esto no funcionará en IE6, 7 u 8 sin embargo. La mejor solución es definir por sí mismo si no está presente:

  1. Mozilla's (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 versión:

    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. roosteronacid de la versión:

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

Tengo curiosidad por saber por qué su versión de la función Mozilla es tan diferente del sitio web al que está enlazando. ¿Lo modificó usted mismo o es solo una versión anterior o algo así? – Shenjoku

+4

@Shenjoku: "respondió Sep 27 '08 a las 15:45" –

+0

Bueno, ahí está mi respuesta jaja. No puedo decir si hay una versión anterior solo mirando el sitio web de mozilla, así que no estaba seguro.No es que importe, solo una curiosidad. En cualquier caso, esto aún fue útil para que puedas obtener un voto positivo;) – Shenjoku

10

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

  1. Elija el elemento central de la matriz.
  2. ¿El elemento que busca es más grande que el elemento que eligió? Si es así, eliminaste la mitad inferior de la matriz. Si no es así, eliminaste la mitad superior.
  3. Elija el elemento medio de la mitad restante de la matriz y continúe como en el paso 2, eliminando las mitades de la matriz restante. Finalmente, encontrará su elemento o no tendrá ninguna matriz para ver.

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

+2

Probablemente deberías mencionar que este enfoque sería más rápido en grande, ordenado matrices que las pequeñas. – roosteronacid

+9

¿por qué sería esto más lento en matrices más pequeñas? – vidstige

+2

@vidstige: Quiere decir que se escala bien, pero no es necesariamente el más rápido para las entradas pequeñas. –

4

He aquí algunos meta-conocimiento para usted - si usted quiere saber lo que puede hacer con una matriz, consulte la documentación - aquí está la página de matriz para Mozilla

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

Allí verás referencia a indexOf, agregado en Javascript 1.6

+2

Weird URL para obtener un manual que contiene información sobre Javascript 1.8 y versiones posteriores. :) –

+0

esto no cubre matrices de objetos como el autor preguntó acerca de – 29er

+0

@VinkoVrsalovic: la URL ha cambiado a https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array –

4

Depende de su propósito. Si programa para la Web, evitar indexOf, no es compatible con Internet Explorador     6 (muchos de ellos todavía se utiliza!), O hacer uso condicional:

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

indexOf es, probablemente, codificada en código nativo, por lo tanto, es más rápido que cualquier cosa que pueda hacer en JavaScript (excepto la búsqueda binaria/dicotomía si la matriz es apropiada). Nota: es una cuestión de gusto, pero me haría un return false; al final de su rutina, para devolver un cierto booleana ...

+0

ha ... Me pongo a pensar que todavía hay un cliente de IE6 en este punto ... – beauXjames

+0

no debería haber un "como de 2008" como en la página de wikipedia para que la gente sepa que esta afirmación es obsoleta –

+2

@ allan.simon Mira mi ícono (y estadísticas) en la parte inferior de mi respuesta. Justo arriba, hay "respuesta Sep 27 '08 a las 16:28". Se llama fecha, y las personas acostumbradas a Stack Overflow miran estas fechas para tomar respuestas con un grano de sal ... Dicho esto, ¡mi biblioteca pública local todavía tiene IE6 instalado en sus computadoras! (¡pero afortunadamente alguien instaló Chrome!) – PhiLho

32

En primer lugar, poner en práctica indexOf en JavaScript para navegadores que no lo tiene .Por ejemplo, vea Erik Arvidsson's array extras (también, associated blog post). Y luego puede usar indexOf sin preocuparse por el soporte del navegador. He aquí una versión ligeramente optimizado de su aplicació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; 
    }; 
} 

Ha cambiado para almacenar la longitud de modo que no tiene que mirar hacia arriba cada iteración. Pero la diferencia no es enorme. Una función de propósito general, menos puede 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; 
    }; 

Yo prefiero usar la función estándar y dejando este tipo de micro-optimización para cuando es realmente necesario. Pero si está interesado en la micro-optimización, he adaptado el benchmarks que roosterononacid vinculado en los comentarios, al benchmark searching in arrays. Sin embargo, son bastante crudos, una investigación completa probaría arreglos con diferentes tipos, diferentes longitudes y encontrar objetos que ocurren en diferentes lugares.

+0

Los ejemplos de código con los que está enlazando son lentos en matrices grandes. Ver los comentarios en mi ejemplo de implementación de una función hasItem(). – roosteronacid

+0

Eche un vistazo a estos puntos de referencia: http://blogs.sun.com/greimer/resource/loop-test.htm For-Loops are slow. Pero supongo que las matrices utilizadas en los puntos de referencia son bastante grandes :) – roosteronacid

+1

http://blogs.sun.com/greimer/resource/loop-test.html – roosteronacid

198

Si está utilizando jQuery:

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

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

+5

Tenga en cuenta que "inArray" es un nombre inapropiado, ya que no devuelve un valor booleano, sino que devuelve el índice del primer elemento encontrado. Entonces, si está comprobando si el elemento existe, debería usar 'if (-1! = $ .inArray (...)) ...'. – johndodo

+0

Útil, pero no creo que sea una respuesta adecuada aquí. La pregunta está etiquetada con "javascript" que indica "vainilla" en mi opinión. :) – iMe

3

una manera robusta para comprobar si un objeto es una matriz de JavaScript se detalla aquí:

Aquí hay dos funciones del marco xa.js que adjunto a un utils = {} 'contenedor'. Esto debería ayudarlo a detectar matrices correctamente.

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 a continuación desea verificar si un objeto está en una matriz, que 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; 
} 
+0

Si bien esto podría responder teóricamente a la pregunta, [sería preferible] (http://meta.stackexchange.com/q/8259) incluir aquí las partes esenciales de la respuesta y proporcionar el enlace de referencia. Además, al copiar/pegar la misma respuesta de solo enlace a varias preguntas muy antiguas a la vez, parece spam. –

+0

Lo siento Bill, realmente no quise que pareciera spam y simplemente estaba tratando de actualizar algunas de las viejas preguntas sobre este tema también. He editado la publicación aquí para incluir la respuesta real en lugar de enlazar. –

+0

@ Bill, en realidad vuelve a leer la pregunta, esto ni siquiera responde en absoluto. Debo haberme equivocado. –

9

asumiendo .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 la segunda arg (bandera) Comparación fuerzas por valor en lugar de referencia

Cuestiones relacionadas