Controlla l'uguaglianza delle variabili rispetto a un elenco di valori


133

Sto verificando una variabile, diciamo foo, per l'uguaglianza con un numero di valori. Per esempio,

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

Il punto è che si tratta piuttosto di un codice per un compito così banale. Ho pensato a quanto segue:

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

ma anche questo non mi piace completamente, perché devo dare valori ridondanti agli oggetti nell'oggetto.

Qualcuno conosce un modo decente di fare un controllo di uguaglianza rispetto a più valori?


Penso che il contesto più ampio debba essere coinvolto quando si decide qualcosa di simile, perché è importante sapere perché si stanno facendo questi confronti.
— Punta il

Bene, in un gioco che sto creando sto controllando i codici della tastiera in modo da decidere quale funzione deve essere chiamata. In diversi browser, una chiave ha diversi codici chiave apparentemente, quindi la necessità di confrontare con più valori.
— pimvdb,

verifica il test delle prestazioni per più metodi, l'operatore logico vince runkit.com/pramendra/58cad911146c1c00147f8d8d
— Pramendra Gupta

Risposte:


175

È possibile utilizzare un array e indexOf:

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

1
Mi piace questa. Sarebbe anche possibile creare una funzione 'contiene' attraverso il prototipo, suppongo, in modo da eliminare l'uso di> -1.
— pimvdb,

1
@pimvdb: tieni presente che potresti aver bisogno della tua implementazione poiché indexOfè disponibile solo dalla quinta edizione di ECMAScript.
— Gumbo,

In un'altra risposta è menzionato anche questo, non lo sapevo, grazie
— pimvdb,

'>' È in qualche modo migliore di '! =='?
— Max Waterman,

117

In ECMA2016 è possibile utilizzare il metodo include . È il modo più pulito che abbia mai visto. (Supportato da tutti i principali browser, tranne IE (Polyfill è nel link)

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

4
Per variabili if([a,b,c].includes(foo))o stringheif(['a','b','c'].includes(foo))
— Hastig Zusammenstellen

per variabili => if([a,b,c].includes(foo))perché le virgolette lo renderanno stringa. @HastigZusammenstellen
— iambinodstha,

2
@BinodShrestha Penso che sia quello che ho scritto, a meno che non mi manchi qualcosa. "Per variabili .. o stringhe ..."
— Hastig Zusammenstellen,

16

Usando le risposte fornite, ho finito con il seguente:

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

Può essere chiamato come:

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

Modifica: ultimamente mi sono imbattuto in questo 'trucco' che è utile se i valori sono stringhe e non contengono caratteri speciali. Per i personaggi speciali diventa brutto a causa della fuga ed è anche più soggetto a errori a causa di ciò.

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

Per essere più precisi, questo controllerà la stringa esatta, ma poi è ancora più complicato per un semplice test di uguaglianza:

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

5
Bontà! Sono stupito che funzioni: inè una parola chiave in Javascript. Ad esempio, l'esecuzione function in() {}; in()causa un errore di sintassi, almeno in Firefox, e non sono sicuro del perché il codice non lo sia. :-)
— Ben Blank

3
Inoltre, è spesso considerata una cattiva pratica da estendere Object.prototype, poiché influisce for (foo in bar)in modo sfortunato. Forse cambiarlo in function contains(obj) { for (var i = 1; i < arguments.length; i++) if (arguments[i] === obj) return true; return false; }e passare l'oggetto come argomento?
— Ben Blank

Grazie per la tua reazione, e anche il compilatore di chiusura di Google restituisce un errore durante la compilazione mentre questo codice stesso funziona perfettamente. Ad ogni modo, è stato suggerito che una classe di supporto può fare questo lavoro meglio che estenderlo, Object.prototypecome hai anche detto. Tuttavia, preferisco così, poiché la notazione per il controllo è adorabile, semplicemente foo.in(1, 2, "test", Infinity), semplice come una torta.
— pimvdb,

E definire una funzione in in()modo regolare non riesce anche su Chrome, ma il prototipo funziona ... :)
— pimvdb

3
L'estensione di Object.prototype è un anti-pattern e non deve essere utilizzato. Utilizzare invece una funzione.
— Vernon,

9

È possibile scrivere if(foo in L(10,20,30))se si definisce Ldi essere

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

    return obj;
};

È ancora più chiaro delle prime risposte, grazie!
— pimvdb,

2
Penso che sia prudente osservare che le funzioni del prototipo sono anche 'in' un array / oggetto - quindi se c'è una funzione 'rimuovi' nel prototipo di un array / oggetto, tornerà sempre vero se si codifica 'remove' in L(1, 3, 12), anche se non lo si è fatto specifica 'rimuovi' da inserire nell'elenco.
— pimvdb,

7

Questo è facilmente estensibile e leggibile:

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

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

Ma non necessariamente più semplice :)


In realtà ho usato questo metodo perché volevo mettere un commento accanto a ciascun valore per descrivere a quale valore si riferiva, questo era il modo più leggibile per raggiungerlo.
— pholcroft,

@pholcroft se hai bisogno di descrivere a cosa si riferisce ogni valore, dovresti creare un enum o una classe e scrivere le tue proprietà per avere nomi descrittivi.
— red_dorian,

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

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

Si noti che indexOf non è nel core ECMAScript. Dovrai avere uno snippet per IE e possibilmente altri browser che non supportano 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;
  };
}

È la copia di Mozilla direttamente. Era troppo pigro per il collegamento. developer.mozilla.org/en/JavaScript/Reference/Global_Objects/…
— meder omuraliev

C'è un motivo per lo spostamento dei bit quando si definisce len se in realtà non si stanno spostando i bit? C'è qualche coercizione implicita in corso qui?
— jaredad7,

3

Inoltre, poiché i valori in base ai quali si sta verificando il risultato sono tutti unici, è possibile utilizzare anche 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

Ora potresti avere una soluzione migliore per risolvere questo scenario, ma in un altro modo che ho preferito.

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    
}

Ho preferito la soluzione sopra all'indice di controllo dove è necessario controllare anche l'indice.

include documenti

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

1

Mi è piaciuta la risposta accettata, ma ho pensato che sarebbe stato utile consentirle di prendere anche array, quindi l'ho estesa a questo:

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

Puoi rimuovere la coercizione del tipo cambiando ==in ===.


1

Se hai accesso a Underscore, puoi utilizzare quanto segue:

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

contains lavorava anche a Lodash (prima di V4), ora devi usare includes

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

1

Questa è una piccola funzione di aiuto:

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

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

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

Maggiori informazioni qui ...


Ottimo approccio: a partire dalla tua idea puoi anche farlo senza una funzione di supporto:const valToCheck = 'E'; const check = ['A', 'B', 'C', 'D'].some(option => option === valToCheck); // false
— Giorgio Tempesta,

Ma una volta che ho iniziato a modificare il codice, ho scoperto che includesdiventa l'opzione migliore, come nella risposta di @ alister:const valToCheck = 'E'; const check = ['A', 'B', 'C', 'D'].includes(valToCheck); // false
— Giorgio Tempesta,

0

Ho semplicemente usato la funzione jArery inArray e una matrice di valori per ottenere questo risultato:

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

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

if(test >= 0) // true

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.