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
}