2013-03-03 16 views
8

Alcune volte nel mio programma, ho dovuto verificare se una variabile era una delle molte opzioni. Per esempioC++ Il modo più efficiente per confrontare una variabile con più valori?

if (num = (<1 or 2 or 3>)) { DO STUFF } 

Ho combinato con "OR", ma niente sembra essere giusto. Ho provato

if (num == (1 || 2 || 3)) 

ma non fa nulla. Per favore aiuto! Grazie in anticipo.

P.S. Devo distinguere tra diversi gruppi. Ad esempio ...

if (num = (1,2,3)) 

else if (num = (4,5,6)) 

else if (num = (7,8,9)) 
+2

è 'se (num == 1 || num == 2 || num == 3)' 'o se (num> = 1 && num <= 3) 'troppa digitazione? Se è più lungo, puoi sempre creare una sorta di array e usare 'std :: find'. – chris

+1

Vedi http://stackoverflow.com/q/14368525/726361 –

+0

Grazie per le risposte rapide. @ Chris, stavo solo cercando qualcosa di un po 'più elegante. –

risposta

6

Se i valori vuoi controllare sono sufficientemente piccoli, potresti creare una maschera di bit dei valori che cerchi e quindi verificare che quel bit sia impostato.

Supponiamo che ti interessi un paio di gruppi.

static const unsigned values_group_1 = (1 << 1) | (1 << 2) | (1 << 3); 
static const unsigned values_group_2 = (1 << 4) | (1 << 5) | (1 << 6); 
static const unsigned values_group_3 = (1 << 7) | (1 << 8) | (1 << 9);  
if ((1 << value_to_check) & values_group_1) { 
    // You found a match for group 1 
} 
if ((1 << value_to_check) & values_group_2) { 
    // You found a match for group 2 
} 
if ((1 << value_to_check) & values_group_3) { 
    // You found a match for group 3 
} 

Questo approccio funziona meglio per valori che non superano le dimensioni naturali con cui la CPU ama lavorare. Questo in genere dovrebbe essere 64 nei tempi moderni, ma può variare a seconda delle specifiche del proprio ambiente.

+0

Freddo. Ciò rende la cosa facile. Se volessi vedere "se 1, altrimenti se 2, altrimenti se 3;" Come potrei farlo? Avrei bisogno di una nuova maschera di bit, o potrei semplicemente aggiungere "(2 << n)"? –

+0

Se si desidera verificare i valori 1, 2 e 3, la maschera bit diventerebbe invece value_i_like = (1 << 1) | (1 << 2) | (1 << 3) ;. –

+0

no, fraintendimenti. Voglio poter differire da (1,2,3) e (4,5,6) –

4

È necessario eseguire il confronto con ciascun valore. Per esempio.

if (num == 1 || num == 2 || num == 3) { stuff } 

Si può anche prendere in considerazione un interruttore e intenzionalmente cadere attraverso i casi (anche se non credo che sia la soluzione migliore per quello che stai affermando).

switch (num) { 
    case 1: 
    case 2: 
    case 3: 
     {DO STUFF} 
     break; 

    default: 
     //do nothing. 
} 
+0

Sì, non esattamente quello che sto cercando. Grazie comunque! –

+1

Umm, no, non hai _have_ per farlo. – einpoklum

2

È possibile definire un insieme di numeri interi, aggiungere i valori desiderati ad esso, e quindi utilizzare il metodo Find per vedere se il valore in questione è nel set

std::set<int> values; 
// add the desired values to your set... 
if (values.find(target) != values.end()) 
    ... 
+0

Questo è un modo interessante di fare le cose ... ci proverò, grazie! –

+0

Scusa, sto solo ricevendo un sacco di errori. Come lo usi esattamente? Potresti fare un esempio? –

+2

lol, genio nella sua semplicità! @TheWalkingCactus usa semplicemente 'count' invece di un' set'. –

14

Ecco un modo in C++ 11, utilizzando std :: initializer_list:

#include <initializer_list> 

template <typename T> 
bool is_in(const T& val, const std::initializer_list<T>& list) 
{ 
    for (const auto& i : list) { 
     if (val == i) { 
      return true; 
     } 
    } 
    return false; 
} 

con questo, si può fare:

if (is_in(num, {1, 2, 3}) { DO STUFF } 

Nota, tuttavia, che le cose come <1 non sono possibili.

+0

Sembra comodo, ma non sto usando 11. Sono solo in plain ol 'C++. –

3

Ho appena avuto un problema simile e mi è venuto a queste C++ 11 soluzioni:

template <class T> 
struct Is 
{ 
    T d_; 
    bool in(T a) { 
    return a == d_; 
    } 
    template <class Arg, class... Args> 
    bool in(Arg a, Args... args) { 
    return in(a) || in(args...); 
    } 
}; 

template <class T> 
Is<T> is(T d) { 
    return Is<T>{d}; 
} 

O come alternativa senza il metodo di terminazione ricorsione. Tieni presente che in questo caso l'ordine dei confronti non è definito e che non si risolve anticipatamente se viene trovata la prima corrispondenza. Ma il codice è più compatto.

template <class T> 
struct Is { 
    const T d_; 
    template <class... Args> 
    bool in(Args... args) { 
    bool r{ false }; 
    [&r](...){}(((r = r || d_ == args), 1)...); 
    return r; 
    } 
}; 

template <class T> 
Is<T> is(T d) { 
    return Is<T>{d}; 
} 

Così, per entrambe le soluzioni il codice sarà simile:

if (is(num).in(1,2,3)) { 
    // do whatever needs to be done 
} 
0

avevo bisogno di fare qualcosa di simile per le enumerazioni. Ho una variabile e desidero testarla su un intervallo di valori.

Qui ho usato una funzione di modello variadic. Notare la specializzazione per il tipo const char*, in modo che is_in(my_str, "a", "b", "c") abbia il risultato previsto per quando my_str memorizza "a".

#include <cstring> 

template<typename T> 
constexpr bool is_in(T t, T v) { 
    return t == v; 
} 

template<> 
constexpr bool is_in(const char* t, const char* v) { 
    return std::strcmp(t,v); 
} 

template<typename T, typename... Args> 
constexpr bool is_in(T t, T v, Args... args) { 
    return t==v || is_in(t,args...); 
} 

Esempio utilizzo:

enum class day 
{ 
    mon, tues, wed, thur, fri, sat, sun 
}; 

bool is_weekend(day d) 
{ 
    return is_in(d, day::sat, day::sun); 
} 
Problemi correlati