Как сократить несколько условий &&

В настоящее время я могу запустить свою программу, но мой код состоит из большого количества повторений, которые выглядят примерно так:

while(option != 'E' && option != 'D' && option != 'P' && option != 'Q' &&
      option != 'e' && option != 'd' && option != 'p' && option != 'q') {
  // Some code here
}

или

while(cType != 'S' && cType != 'L' && cType != 'O' && cType != 'Q' &&
      cType != 's' && cType != 'l' && cType != 'o' && cType != 'q') {
  // Some code here
}

Какой самый быстрый способ сократить код?

(Есть ли способ использовать дополнительную функцию?)

Ответ 1

const char invalidChars[] = "edpq";
while (strchr(invalidChars, tolower(option)) != 0) {
    ...
}

Ответ 2

Вы можете инициализировать строку, содержащую символы, которые вы хотите сопоставить, затем используйте find, который возвращает npos, если совпадение не найдено:

string match = "SLOQsloq";
while (match.find(cType) == string::npos)
  ...

Ответ 3

Вы можете избавиться от половины условий с помощью std::tolower

while(std::tolower(option) != 'e' && std::tolower(option) != 'd' && std::tolower(option) != 'p' && std::tolower(option) != 'q')

Вы также можете использовать std::string и find функция-член как:

std::string options = "edpq";
//...
while (options.find(std::tolower(option)) == std::string::npos)

Ответ 4

Вы можете упростить логику и сделать чтение более понятным с помощью std::set и проверить, содержит ли набор (или не содержит ) переменную, которую мы сравниваем с:

std::set<char> someChars { 'a', 'b', 'c' };
if(someChars.find(myChar) != someChars.end()) {
    // myChar is either 'a', 'b', or 'c'
}

Условие на большинстве других языков будет написано более чисто, как что-то вроде someChars.contains(myChar) (но интерфейс С++ установлен очень минимален).

Однако для небольшого количества сравнений ваш метод, вероятно, быстрее.

Ответ 5

Быстрый тест кандидата без ветвления.

1) Делать без дела.
2) Форма продукта из 4 отличий.
3) 1 сравнивают с 0.

Принимаются только буквы.
Работает до 4 (sizeof int/sizeof char) букв.
Верхний/нижний регистр отличается одним и тем же битом. (Это работает с ASCII и EBCDIC)

#define CaseMaskBits ((unsigned char)~('A'^'a'))
#define Product4(ch, s) ((ch-s[0]) * (ch-s[1]) * (ch-s[2]) * (ch-s[3]))
#define TestEq4(ch, t, s)  (t=ch&CaseMaskBits, !Product4(t, s))

int main(void) {
  int ch;
  printf("%X\n", CaseMaskBits);
  for (ch = 0; ch < 256; ch++){
    int t;  // temp var for TestEQ4
    while (TestEq4(ch, t, "ELPQ")) {
      printf("%d %c\n", ch, ch);
      break;
    }
  }
  return 0;
}

280           while (TestEq4(ch, t, "ELPQ")) {
00402560:   mov %ebx,%eax
00402562:   and $0xdf,%eax
00402567:   lea -0x4c(%eax),%edx
0040256a:   lea -0x45(%eax),%ecx
0040256d:   imul %edx,%ecx
00402570:   lea -0x50(%eax),%edx
00402573:   sub $0x51,%eax
00402576:   imul %ecx,%edx
00402579:   imul %edx,%eax
0040257c:   test %eax,%eax
0040257e:   jne 0x402555 <main+37>
281             printf("%d %c\n", ch, ch);

Ответ 6

Если option/cType имеет <= 8 бит значения, для скорости, используйте поиск таблицы. @Dieter Lücking

unsigned char Table[UCHAR_MAX + 1] = {
  fill per needs };
#define Table_OptionMask 1
#define Table_cTypeMask 2
#define Table_nextMask 4

while (!(Table[(unsigned char)option] & Table_OptionMask)) ...
while (!(Table[(unsigned char)cType] & Table_cTypeMask)) ...

Для более простого обслуживания кода заполните таблицу при запуске кода, вызвав Table_Setup().

static void Table_SetInsensitive(unsigned char *Table, unsigned mask, cnst char *src) {
  while (*src) {
    Table[toupper((unsigned char) *src)] |= mask;
    Table[tolower((unsigned char) *src)] |= mask;
    src++;  
  }
}

void Table_Setup(void) {
  memset(Table, 0, sizeof Table);
  Table_SetInsensitive(Table, Table_OptionMask, "EDPQ");
  Table_SetInsensitive(Table, Table_cTypeMask, "SLOQ");
  Table_SetInsensitive(Table, Table_cTypeMask, tbd);
}