Verifique la igualdad de variables con una lista de valores


133

Estoy comprobando una variable, por ejemplo foo, para la igualdad de varios valores. Por ejemplo,

if( foo == 1 || foo == 3 || foo == 12 ) {
    // ...
}

El punto es que es bastante código para una tarea tan trivial. Se me ocurrió lo siguiente:

if( foo in {1: 1, 3: 1, 12: 1} ) {
    // ...
}

pero tampoco me atrae por completo, porque tengo que dar valores redundantes a los elementos del objeto.

¿Alguien sabe una forma decente de hacer una verificación de igualdad contra múltiples valores?


Creo que el contexto más amplio debe estar involucrado al decidir algo como esto, porque es importante saber por qué estás haciendo tales comparaciones.
Puntiagudo

Bueno, en un juego que estoy creando, compruebo los códigos del teclado para decidir qué función se debe llamar. En diferentes navegadores, una clave tiene diferentes códigos de tecla aparentemente, de ahí la necesidad de comparar con múltiples valores.
pimvdb

compruebe la prueba de rendimiento para varios métodos, el operador lógico gana runkit.com/pramendra/58cad911146c1c00147f8d8d
Pramendra Gupta

Respuestas:


175

Podría usar una matriz y indexOf:

if ([1,3,12].indexOf(foo) > -1)

1
Me gusta este. Incluso sería posible crear una función 'contiene' a través del prototipo, supongo, para eliminar el uso de> -1.
pimvdb

1
@pimvdb: Tenga en cuenta que es posible que necesite su propia implementación, ya indexOfque solo está disponible desde la 5ta edición de ECMAScript.
Gumbo

En otra respuesta esto se menciona como bien de hecho, no sabía que, gracias
pimvdb

¿Es '>' de alguna manera mejor que '! =='?
Max Waterman

117

En ECMA2016 puede utilizar la incluye método. Es la forma más limpia que he visto. (Compatible con todos los principales navegadores, excepto IE (Polyfill está en el enlace)

if([1,3,12].includes(foo)) {
    // ...
}

44
Para las variables if([a,b,c].includes(foo))o cadenasif(['a','b','c'].includes(foo))
hastig Zusammenstellen

para variables => if([a,b,c].includes(foo))porque las comillas lo convertirán en cadena. @HastigZusammenstellen
iambinodstha

2
@BinodShrestha Creo que eso es lo que escribí, a menos que me falte algo. "Para variables ... o cadenas ..."
Hastig Zusammenstellen

16

Usando las respuestas proporcionadas, terminé con lo siguiente:

Object.prototype.in = function() {
    for(var i=0; i<arguments.length; i++)
       if(arguments[i] == this) return true;
    return false;
}

Se puede llamar así:

if(foo.in(1, 3, 12)) {
    // ...
}

Editar: Me encontré con este 'truco' últimamente que es útil si los valores son cadenas y no contienen caracteres especiales. Para los caracteres especiales se vuelve feo debido al escape y también es más propenso a errores debido a eso.

/foo|bar|something/.test(str);

Para ser más precisos, esto verificará la cadena exacta, pero nuevamente es más complicado para una simple prueba de igualdad:

/^(foo|bar|something)$/.test(str);

55
¡Bondad! Me sorprende que funcione, ines una palabra clave en Javascript. Por ejemplo, ejecutar function in() {}; in()resultados en un error de sintaxis, al menos en Firefox, y no estoy seguro de por qué su código no lo hace. :-)
Ben Blank

3
Además, a menudo se considera una mala práctica extender Object.prototype, ya que afecta for (foo in bar)de manera desafortunada. ¿Quizás cambiarlo function contains(obj) { for (var i = 1; i < arguments.length; i++) if (arguments[i] === obj) return true; return false; }y pasar el objeto como argumento?
Ben Blank

Gracias por su reacción, y el Compilador de cierre de Google también devuelve un error al compilar mientras este código funciona de manera excelente. De todos modos, se ha sugerido que una clase auxiliar puede hacer este trabajo mejor que extender Object.prototypecomo también mencionas. Sin embargo, prefiero de esta manera, ya que la notación para la comprobación es encantadora foo.in(1, 2, "test", Infinity), sencilla y sencilla.
pimvdb

Y definir una función de in()la manera normal también falla en Chrome, pero el prototipo funciona ... :)
pimvdb

3
Extender el Object.prototype es un antipatrón y no debe usarse. Use una función en su lugar.
Vernon

9

Puede escribir if(foo in L(10,20,30))si define Lser

var L = function()
{
    var obj = {};
    for(var i=0; i<arguments.length; i++)
        obj[arguments[i]] = null;

    return obj;
};

Eso es incluso más claro que las respuestas anteriores, ¡gracias!
pimvdb

2
Creo que es prudente señalar que las funciones prototipo también están 'en' una matriz / objeto, por lo que si hay una función 'eliminar' en un prototipo de matriz / objeto, siempre devolverá verdadero si codifica 'remove' in L(1, 3, 12), aunque no lo hizo especifique 'eliminar' para colocar en la lista.
pimvdb

7

Esto es fácilmente extensible y legible:

switch (foo) {
    case 1:
    case 3:
    case 12:
        // ...
        break

    case 4:
    case 5:
    case 6:
        // something else
        break
}

Pero no necesariamente más fácil :)


De hecho, utilicé este método porque quería poner un comentario al lado de cada valor para describir con qué se relacionaba el valor, esta era la forma más fácil de lograrlo.
pholcroft

@pholcroft si necesita describir con qué se relaciona cada valor, debe crear una enumeración o clase, y escribir sus propiedades para tener nombres descriptivos.
red_dorian

6
var a = [1,2,3];

if ( a.indexOf( 1 ) !== -1 ) { }

Tenga en cuenta que indexOf no está en el núcleo ECMAScript. Deberá tener un fragmento para IE y posiblemente otros navegadores que no admitan Array.prototype.indexOf.

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

Es la copia de Mozilla directamente. Era demasiado vago para vincular. developer.mozilla.org/en/JavaScript/Reference/Global_Objects/…
meder omuraliev

¿Hay alguna razón para el cambio de bits cuando define len si en realidad no está cambiando bits? ¿Hay alguna coerción implícita aquí?
jaredad7

3

Además, dado que los valores con los que está comprobando el resultado son únicos, también puede usar Set.prototype.has () .

var valid = [1, 3, 12];
var goodFoo = 3;
var badFoo = 55;

// Test
console.log( new Set(valid).has(goodFoo) );
console.log( new Set(valid).has(badFoo) );


2

Ahora puede tener una mejor solución para resolver este escenario, pero de otra manera que prefiero.

const arr = [1,3,12]
if( arr.includes(foo)) { // it will return true if you `foo` is one of array values else false
  // code here    
}

Preferí la solución anterior sobre la verificación indexOf donde también necesita verificar el índice.

incluye documentos

if ( arr.indexOf( foo ) !== -1 ) { }

1

Me gustó la respuesta aceptada, pero pensé que sería bueno permitirle tomar matrices también, así que la expandí a esto:

Object.prototype.isin = function() {
    for(var i = arguments.length; i--;) {
        var a = arguments[i];
        if(a.constructor === Array) {
            for(var j = a.length; j--;)
                if(a[j] == this) return true;
        }
        else if(a == this) return true;
    }
    return false;
}

var lucky = 7,
    more = [7, 11, 42];
lucky.isin(2, 3, 5, 8, more) //true

Puede eliminar la coerción de tipo cambiando ==a ===.


1

Si tiene acceso a Underscore, puede usar lo siguiente:

if (_.contains([1, 3, 12], foo)) {
  // ...
}

contains solía trabajar en Lodash también (antes de V4), ahora tienes que usar includes

if (_.includes([1, 3, 12], foo)) {
  handleYellowFruit();
}

1

Esta es una pequeña función de ayuda auxiliar:

const letters = ['A', 'B', 'C', 'D'];

function checkInList(arr, val) {
  return arr.some(arrVal => val === arrVal);
}

checkInList(letters, 'E');   // false
checkInList(letters, 'A');   // true

Más información aquí ...


Muy buen enfoque: a partir de su idea, también puede hacerlo sin una función auxiliar:const valToCheck = 'E'; const check = ['A', 'B', 'C', 'D'].some(option => option === valToCheck); // false
Giorgio Tempesta

Pero una vez que comencé a ajustar el código, descubrí que se includesconvierte en la mejor opción, como en la respuesta de @ alister:const valToCheck = 'E'; const check = ['A', 'B', 'C', 'D'].includes(valToCheck); // false
Giorgio Tempesta

0

Simplemente utilicé la función jQuery inArray y una matriz de valores para lograr esto:

myArr = ["A", "B", "C", "C-"];

var test = $.inArray("C", myArr)  
// returns index of 2 returns -1 if not in array

if(test >= 0) // true

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.