c++ if-statement while-loop simplify

c++ - ¿Hay alguna manera de acortar esto mientras que la condición?



if-statement while-loop (9)

while (temp->left->oper == ''+'' || temp->left->oper == ''-'' || temp->left->oper == ''*'' || temp->left->oper == ''/'' || temp->right->oper == ''+'' || temp->right->oper == ''-'' || temp->right->oper == ''*'' || temp->right->oper == ''/'') { // do something }

Para mayor claridad: temp es un puntero que apunta a esta estructura:

struct node { int num; char oper; node* left; node* right; };


"+" "-" "*" y "/" son valores decimales ASCII 42, 43, 45 y 47 por lo tanto

#define IS_OPER(x) (x > 41 && x < 48 && x != 44 && x != 46) while(IS_OPER(temp->left->oper || IS_OPER(temp->right->oper){ /* do something */ }


Al intercambiar espacio contra tiempo, podría construir dos matrices "booleanas" indexadas por temp->left->oper temp->left->oper y temp->left->oper , respectivamente. La matriz correspondiente contiene verdadero cuando se cumple la condición, de lo contrario es falso . Asi que:

while (array1[temp->left->oper] || array1[temp->right->oper]) { // do something }

Como los conjuntos de izquierda y derecha parecen idénticos, una matriz realmente funcionará.

La inicialización sería así:

static char array1[256]; // initialized to "all false"

...

array1[''+''] = array1[''-''] = array1[''*''] = array1[''/''] = ''/001'';

Similar para array2 . Como los saltos son malos para las CPU de canalización modernas, incluso podría usar una tabla más grande como esta:

while (array1[temp->left->oper << 8 | temp->right->oper]) { // do something }

Pero la inicialización es más complicada:

static char array1[256 * 256]; // initialized to "all false"

...

void init(char c) { for (unsigned char i = 0; i <= 255; ++i) { array1[(c << 8) | i] = array1[(i << 8) | c] = ''/001''; } } init(''+''); init(''-''); init(''*''); init(''/'');


Claro, podría usar una cadena de operadores válidos y buscarlo.

#include <cstring> // : : const char* ops = "+-*/"; while(strchr(ops, temp->left->oper) || strchr(ops, temp->right->oper)) { // do something }

Si le preocupa el rendimiento, tal vez las búsquedas en la tabla:

#include <climits> // : : // Start with a table initialized to all zeroes. char is_op[1 << CHAR_BIT] = {0}; // Build the table any way you please. This way using a string is handy. const char* ops = "+-*/"; for (const char* op = ops; *op; op++) is_op[*op] = 1; // Then tests require no searching while(is_op[temp->left->oper] || is_op[temp->right->oper]) { // do something }


Crea una subfunción,

bool is_arithmetic_char(char) { // Your implementation or one proposed in another answers. }

y entonces:

while (is_arithmetic_char(temp->left->oper) || is_arithmetic_char(temp->right->oper)) { // do something }


Estilo C:

int cont = 1; while(cont) switch(temp->left->oper) { case ''+'': case ''-'': ... case ''/'': // Do something break; default: cont = 0; }

Es posible que deba encerrar // Do something con llaves para declarar variables.


La programación es el proceso de encontrar redundancias y eliminarlas.

struct node { int num; char oper; node* left; node* right; }; while (temp->left->oper == ''+'' || temp->left->oper == ''-'' || temp->left->oper == ''*'' || temp->left->oper == ''/'' || temp->right->oper == ''+'' || temp->right->oper == ''-'' || temp->right->oper == ''*'' || temp->right->oper == ''/'') { // do something }

¿Cuál es la "unidad repetida" aquí? Bueno, veo dos instancias de

(something)->oper == ''+'' || (something)->oper == ''-'' || (something)->oper == ''*'' || (something)->oper == ''/''

Así que factoricemos esa parte repetida en una función, de modo que solo tengamos que escribirla una vez.

struct node { int num; char oper; node* left; node* right; bool oper_is_arithmetic() const { return this->oper == ''+'' || this->oper == ''-'' || this->oper == ''*'' || this->oper == ''/''; } }; while (temp->left->oper_is_arithmetic() || temp->right->oper_is_arithmetic()) { // do something }

Ta-da! ¡Acortado!
(Código original: 17 líneas, 8 de las cuales son la condición del bucle. Código revisado: 18 líneas, 2 de las cuales son la condición del bucle).


Puede construir una cadena que contenga las opciones y buscar el carácter:

#include <string> // ... for (auto ops = "+-*/"s; ops.find(temp-> left->oper) != std::string::npos || ops.find(temp->right->oper) != std::string::npos;) /* ... */;

El "+-*/"s es una característica de C ++ 14. Use std::string ops = "+-*/"; antes de C ++ 14.


Regex al rescate!

#include <regex> while ( std::regex_match(temp->left->oper, std::regex("[/+/-/*//]")) || std::regex_match(temp->right->oper, std::regex("[/+/-/*//]")) ) { // do something }

EXPLICACIÓN: Los corchetes de expresiones regulares [] denotan una "clase de caracteres" de expresiones regulares. Esto significa "hacer coincidir cualquier carácter que aparezca entre corchetes". Por ejemplo, g[eiou]t coincidiría con "get", "git", "got" y "gut", pero NO con "gat". Las barras invertidas son necesarias porque más (+) menos (-) y estrella (*) y barra diagonal (/) tienen significado dentro de una clase de caracteres.

DESCARGO DE RESPONSABILIDAD: No tengo tiempo para ejecutar este código; Puede que tenga que modificarlo, pero se entiende la idea. Puede que tenga que declarar / convertir oper de un char a un std::string .

Referencias
1. http://www.cplusplus.com/reference/regex/regex_match/
2. https://www.rexegg.com/regex-quickstart.html
3. https://www.amazon.com/Mastering-Regular-Expressions-Jeffrey-Friedl/dp/0596528124/ref=sr_1_1?keywords=regex&qid=1563904113&s=gateway&sr=8-1


Sí, de hecho puedes!

Almacene los caracteres válidos en una std::array o incluso en una matriz simple y aplique el algoritmo estándar std::any_of para verificar la condición.

#include <array> // std::array #include <algorithm> // std::any_of const std::array<char, 4> options{ ''+'', ''-'', ''*'', ''/'' }; const auto tester = [&temp](char c) { return temp->left->oper == c || temp->right->oper == c; }; const bool isValid = std::any_of(options.cbegin(), options.cend(), tester); while(isValid) // now the while-loop is simplified to { // do something }

Esto se puede limpiar más empacando en una función, que acepta el objeto de node a verificar.

#include <array> // std::array #include <algorithm> // std::any_of bool isValid(const node& temp) { static constexpr std::array<char, 4> options{ ''+'', ''-'', ''*'', ''/'' }; const auto tester = [&temp](char c) { return temp->left->oper == c || temp->right->oper == c; }; return std::any_of(options.cbegin(), options.cend(), tester); }

que se puede llamar en el while-loop

while (isValid(temp)) // pass the node to be checked { // do something }