Foros del Web » Programación para mayores de 30 ;) » C/C++ »

¿Como quitar tantos IF?

Estas en el tema de ¿Como quitar tantos IF? en el foro de C/C++ en Foros del Web. Hola Imaginar un código del siguiente tipo: Código: #define PEPE 1 #define JUAN 2 #define ANTONIO 3 #define MANUEL 4 ... //Vamos, muchos defines //Y ...
  #1 (permalink)  
Antiguo 16/06/2006, 02:03
Avatar de javimartinez  
Fecha de Ingreso: marzo-2003
Ubicación: Leganés (Madrid)
Mensajes: 284
Antigüedad: 21 años, 1 mes
Puntos: 1
Pregunta ¿Como quitar tantos IF?

Hola

Imaginar un código del siguiente tipo:
Código:
#define PEPE 1
#define JUAN 2
#define ANTONIO 3
#define MANUEL 4
... //Vamos, muchos defines


//Y luego, en alguna función una serie de IFs del siguiente tipo

char *cadena;

cadena = objeto.ObtenerPersona();

if (!strcmp(cadena, "PEPE"))
   return PEPE;
else if (!strcmp(cadena, "JUAN"))
   return JUAN;
else if (!strcmp(cadena, "ANTONIO"))
   return ANTONIO;
else if (!strcmp(cadena, "MANUEL"))
   return MANUEL;
//Así n veces
Mi duda es, ¿hay alguna forma de optimizar esto y no tener tantos IF?. Es decir, algo q permita asociar la cadena de tipo char * a la constante que manejas interiormente????

Gracias y un saludos :)
__________________
Javi Martínez

Web: Acertijolandia Blog: A Entretenerse
  #2 (permalink)  
Antiguo 16/06/2006, 02:41
ANR
 
Fecha de Ingreso: octubre-2005
Mensajes: 15
Antigüedad: 18 años, 7 meses
Puntos: 0
Con un Switch


switch (<variable>)
{
case <expresión_constante>: [<sentencias>] [break;]
. . .
[default : [<sentencia>]]
}
  #3 (permalink)  
Antiguo 16/06/2006, 02:46
Avatar de javimartinez  
Fecha de Ingreso: marzo-2003
Ubicación: Leganés (Madrid)
Mensajes: 284
Antigüedad: 21 años, 1 mes
Puntos: 1
El problema es que la variable del switch es una cadena de caracteres, por lo tanto, si no me equivoco, no funciona, ya que el switch no va con cadenas no???

Edito: ná, lo recomprobé por si acaso y como esperaba, no se puede hacer un switch con una cadena en la variable.
__________________
Javi Martínez

Web: Acertijolandia Blog: A Entretenerse

Última edición por javimartinez; 16/06/2006 a las 02:52
  #4 (permalink)  
Antiguo 16/06/2006, 08:49
Avatar de yournightmare86  
Fecha de Ingreso: abril-2006
Ubicación: Madrid
Mensajes: 875
Antigüedad: 18 años
Puntos: 9
Los switch también pueden funcionar con cadenas. case 'A', case 'b' etc etc.
También podrías usar la siguiente estructura, que es usando el interrogante y los 2 puntos.Ejemplo:
isupper(c=getchar())? printf("\n Es mayuscula) : printf("\n No es mayuscula.");

Si se cumple la condición expuesta antes del interrogante se ejecuta lo que está a la izqda de los 2 puntos. Si no se cumple se ejecuta lo de la derecha. Esto es como un if-else pero también puedes anidar varios en una sola línea...
  #5 (permalink)  
Antiguo 16/06/2006, 10:34
Avatar de Instru  
Fecha de Ingreso: noviembre-2002
Ubicación: Mexico
Mensajes: 2.751
Antigüedad: 21 años, 6 meses
Puntos: 52
Lo ideal es que crees una especie de "base de datos", es decir, un array de estructuras con todos los valores posibles:
struct _base {
char nombre[32];
int valor;
};
struct _base base[]={{"JUAN", 1}, {"PEPE", 2}};

Despues:

for(int i=0; i<MAX; i++)
{
if(strcmp(cadena, base[i].nombre)==0)
return base[i].valor;
}

Y listo, en teoria eso te debe jalar muy bien.

Saludos
  #6 (permalink)  
Antiguo 16/06/2006, 10:39
Avatar de Instru  
Fecha de Ingreso: noviembre-2002
Ubicación: Mexico
Mensajes: 2.751
Antigüedad: 21 años, 6 meses
Puntos: 52
Cita:
Los switch también pueden funcionar con cadenas. case 'A', case 'b' etc etc.
También podrías usar la siguiente estructura, que es usando el interrogante y los 2 puntos.Ejemplo:
isupper(c=getchar())? printf("\n Es mayuscula) : printf("\n No es mayuscula.");
Estas en un error. 'A' No es una cadena. Es simplemente una valor.
Una cadena como su nombre lo indica son varios elementes encadenados A-B-C...

Lo que tu mencionas como "estructura", no es estructura. Es una sentencia o instruccion. Finalmente es lo mismo que un if-else solito.

El switch case no soporta cadenas, solo valores numericos o un solo caracter(que en si es lo mismo). Y en realidad un switch-else es igualito a un if-else.

Espero que hayan servido las aclaraciones.

Saludos
  #7 (permalink)  
Antiguo 16/06/2006, 10:48
Avatar de javimartinez  
Fecha de Ingreso: marzo-2003
Ubicación: Leganés (Madrid)
Mensajes: 284
Antigüedad: 21 años, 1 mes
Puntos: 1
Gracias por la sugerencia Instru :) pensaré si utilizarla o no el lunes, ya que el código queda un poco más elegante que poner 50 IFs seguidos. Lo único, que es un pelín más ineficiente, pero no creo que se note mucho.

yournightmare86, como ya te ha comentado Instru, lo que tu pones ('A', 'B'...) no son cadenas de caracteres, si no que simplemente es un caracter, lo que si sirve para un switch, ya que realmente cada carácter se corresponde con un número según el código ascii, así que internamente es como realizarlo con enteros.

Un saludo y gracias a todos por contestar :)
__________________
Javi Martínez

Web: Acertijolandia Blog: A Entretenerse
  #8 (permalink)  
Antiguo 16/06/2006, 12:03
 
Fecha de Ingreso: mayo-2006
Mensajes: 40
Antigüedad: 18 años
Puntos: 0
Con la solucion que te propuso Instru resolverias el poner una cadena numerosa de if's en tu codigo, pero de cualquier manera el programa efectuaria ese numero de if's y llamaria a la funcion strcmp para cada cadena. Si tu tuvieras que comparar una cadena en , digamos 1000 nombres, entonces tendrias que efectuar 1000 comparaciones en caso de que la cadena que le dieras no se encontrara en la lista de nombres.
Otra solucion podria ser crear una maquina de estados finitos para el conjunto de nombres. Te pongo un ejemplo sencillo con tres nombres, digamos, ANA, ANASTACIA y ANDREA, y supongamos que la cadena que quieres comparar para ver si esta entre estos nombres es ANTONIO. A la maquina le vas dando letra por letra y avanza a otro estado de acuerdo a estas letras. Por ejemplo la maquina esta al principio en el estado 0. Si le das una letra distinta de 'A' no avanza hacia ningun estado y concluyes que la cadena que le estas dando no concuerda con ninguno de los tres nombres. En este caso le das la letra 'A' que es la primera de ANTONIO. La maquina avanza hacia el estado 1. En este estado la unica letra que le puedes dar para que avanze hacia el estado 2 es la letra 'N', que es el caso en la segunda letra de ANTONIO. A partir del estado 1 la maquina puede avanzar al estado 3 si le das la letra 'A' (la tercera letra de ANA y ANASTACIA) o al estado 4 si le das la letra 'D' (la tercera letra de ANDREA). En este caso la tercera letra de ANTONIO es 'T', por lo que no podrias avanzar hacia ningun estado y concluirias que la cadena ANTONIO no pertenece al conjunto de nombres.
Bueno no se si te queda claro que haciendo esta maquina no tendrias que hacer 1000 comparaciones en caso de que tuvieras 1000 nombres, claro que la maquina ocuparia un buen numero de bytes de acuerdo a la cantidad de nombres y es mas trabajo de programacion que haciendo el simple for que te propuso Instru
  #9 (permalink)  
Antiguo 16/06/2006, 12:13
Avatar de Instru  
Fecha de Ingreso: noviembre-2002
Ubicación: Mexico
Mensajes: 2.751
Antigüedad: 21 años, 6 meses
Puntos: 52
Vamos, la eeficiencia es impersiptible. Es un programa en si sencillo y al menos que tubierras 2 millones de nombres pues ahi tardaria unos cuantos segundos.

Pero checa las ventajas.
-Te deshaces todos los defines. Con la estructura, no necesitas tener tantos defines....de hecho ninguno, ya que el nombre esta internamente relacionado con un numero dentro de la estructura.
-Te ahorras horas de trabajo. En vez de escribir 512 comparaciones a mano, solo escribes la "base de datos" y el for te resuelve la vida.
-Es reutilizable. Solo tienes que agregar mas nombres a la "base de datos" y aumentar el numero de MAX y el for solito se encarga de funcionar sin que lo modifiques.

Ya si quieres manejar mucha mas informacion(algunos millones de datos diferentes) te recomendaria que aprendas los que son las verdaderas Bases de datos(SQL, por ejemplo).

La solucion que te plantea pitukilloloco no esta nada mal, mas este tipo de soluciones se utilizan para cosas mas especificas, no tan generales como la que pides.

Saludos
  #10 (permalink)  
Antiguo 16/06/2006, 15:14
Avatar de javimartinez  
Fecha de Ingreso: marzo-2003
Ubicación: Leganés (Madrid)
Mensajes: 284
Antigüedad: 21 años, 1 mes
Puntos: 1
pufffff, el problema no es tan complicado como para bases de datos ni autómatas finitos, en realidad el número de posibles cadenas rondará entre los 30 y 50 como mucho de ahí que seguramente termine cogiendo la opción del bucle for.

pitukilloloco, el problema que le veo a la utilización de un autómata finito para esto es el gran número de estados que se generaría. Imaginate tener 1000 cadenas distintas de entre 5-10 caracteres tan solo, pues tendrías que programarte miles de estados. Ahora bien, también es verdad que sería lo más eficiente en ejecución, pero creo que no compensa. Por otra parte, la programación se podría simplificar mucho utilizando alguna herramienta tipo Lex (herramienta para análisis léxico de lenguajes que se podría utilizar para construir el autómata)

Otra solución que tenía en mente para quitar ejecuciones de strcmp era la de IF "balanceados" (por llamarle de alguna forma). Básicamente sería ordenar todas las posibles cadenas y preguntar por la del medío, tipo las búsquedas ¿dicotómicas? (no recuerdo si este era el nombre exacto).

Instru, respecto a las ventajas que indicas:

- Quitar los defines es justo lo que no quiero. Los define los tengo simplemente para facilitar la lectura del código y su futuro mantenimiento, ya que dicho número se utilizará en multitud de lugares del código y siempre se entenderá mejor algo tipo persona==PEPE que persona==23.

- En la segunda y la tercera estoy totalmente de acuerdo, y es lo q me inclina a tomar esa solución.

Saludos y muchas gracias por contestar a los 2 :)
__________________
Javi Martínez

Web: Acertijolandia Blog: A Entretenerse
  #11 (permalink)  
Antiguo 16/06/2006, 16:09
 
Fecha de Ingreso: abril-2006
Ubicación: Acapulco Gro. México
Mensajes: 483
Antigüedad: 18 años
Puntos: 2
Depende en gran pare de lo que quieres lograr y como se tienen que lograr,

si en tu ejemplo ya tienes los nombres predefinidos, esto implica que se conosen los posibles nombres a ingresar, si es asi, slo bastaria con un menu.


1.- PEPE
2.- JUAN
3.- ANTONIO
4.- MANUEL
5.-...
ect...

de esta forma solo se ingresaria el indice del nombre en menu.

scanf("%d", &index);

y esto ya lo puedes usar de 2 formas:

con un:
switch(index)
{
case 1:
case 2:
case 3:
case 4:
etc....
}

o con cun

nombres[index-1];

con switch puedes usar los defines o un array con cadenas
en el segundo caso solo con el array de cadenas predefinidas.


pero te repito esto dependera de como y que hara tu aplicacion.
si lo que quieres es que adivine el nombre ingresado pues la opcion a usar seria la planteada por Instru.

Saludos.

Última edición por Nivel7; 16/06/2006 a las 16:14
  #12 (permalink)  
Antiguo 16/06/2006, 17:13
Avatar de javimartinez  
Fecha de Ingreso: marzo-2003
Ubicación: Leganés (Madrid)
Mensajes: 284
Antigüedad: 21 años, 1 mes
Puntos: 1
puffffff, esto cada vez se aleja más de la pregunta original. La duda inicial era como pasar directamente de una cadena, por ej "AAA" a un entero representado con un define con el mismo nombre de la cadena básicamente. Y la cosa a terminado yendose a autómatas finitos y ahora a menus por pantalla (jodio lo del menú, sobretodo cuando la cadena es la cabecera de un paquete que te llega por un socket y q es así por narices)

De todas formas, gracias por contestar Nivel 7, la verdad es que este post me está sirviendo para coger buenas ideas para problemas futuros.

Saludos :)
__________________
Javi Martínez

Web: Acertijolandia Blog: A Entretenerse
  #13 (permalink)  
Antiguo 16/06/2006, 18:23
 
Fecha de Ingreso: mayo-2006
Mensajes: 40
Antigüedad: 18 años
Puntos: 0
No serian tantos estados como supones. Lo serian si lo aplicaras mecanicamente para cada letra que componen el total de los nombres. Supon que tengo exactamente 26 nombres, cada uno de los cuales comienzan con cada una de las letras del alfabeto (abcdefghijklmnopqrstuvwxyz), entonces, independientemente de que tan grandes sean estos nombres (podrian ser frases de muchos caracteres), aqui solo tendria una maquina con 26 estados. Si quisiera ver si una cadena esta entre los 26 nombres iria al estado correspondiente de acuerdo a la primera letra de la cadena y a partir de ahi solo tendria que comparar el resto de la cadena con un solo nombre, el que comienza con la primera letra que corresponde a ese estado. O sea, si ves la maquina de estados como un arbol que comienza del estado 0 y se bifurca en 26 estados, y a su vez cada uno de estos se bifurca en otros 26, y a su vez ... entonces los estados se irian formando con las letras que tienen en comun los nombres en cada nivel de este arbol y un nodo seria una hoja cuando ya no hubiera letras en comun y si una cadena, al analizarla llega a un estado hoja, a partir de ahi solo se tiene que comparar con el resto del nombre que lleva a esa hoja.
  #14 (permalink)  
Antiguo 16/06/2006, 19:06
Avatar de Instru  
Fecha de Ingreso: noviembre-2002
Ubicación: Mexico
Mensajes: 2.751
Antigüedad: 21 años, 6 meses
Puntos: 52
Cita:
Instru, respecto a las ventajas que indicas:

- Quitar los defines es justo lo que no quiero. Los define los tengo simplemente para facilitar la lectura del código y su futuro mantenimiento, ya que dicho número se utilizará en multitud de lugares del código y siempre se entenderá mejor algo tipo persona==PEPE que persona==23.

- En la segunda y la tercera estoy totalmente de acuerdo, y es lo q me inclina a tomar esa solución.

Saludos y muchas gracias por contestar a los 2 :)
Bueno, eso es un error...
Digo, para mi es mucho mas dificil ver PEPE y tener que buscar los defines para encontrarme que PEPE significa 23, por ejemplo. Es un poco absurdo tener tantos defines.

Aparte la estructura que te recomiendo que hagas te hace el mismo trabajo ya que te relacion directamente el nombre ya en cadena con un numero.
No necesitas los defines, porque has de cuenta que tu al querer el numero de una nombre, solo lo haces basandote en la estructura, por ejemplo:

strcpy(base[5].nombre, "PEPE");
base[5].numero=15;

Y asi tienes por seguro que cuando quieras saber que numero es PEPE, con el ciclo for lo encuentras sin problemas.
Aparte te puedes ayudar de algunas funciones, por ejemplo.

int buscar_numero(char *nombre);
La podrias hacer para que te olvides sobre los fors y con llamar a la funcion ya obtienes lo que necesites.

Digo, para mi es la manera mas eficiente, elgante y comoda.

Espero haberte ayudado. Ya de aqui, si decides optar por los defines, ya es tu desicion.

Saludos
  #15 (permalink)  
Antiguo 16/06/2006, 22:14
 
Fecha de Ingreso: abril-2006
Ubicación: Acapulco Gro. México
Mensajes: 483
Antigüedad: 18 años
Puntos: 2
Si mencionaras esto en un principio la respuesta seria diferente, pero en el mensaje inicial no mencionas nada de Sockets o algo por el estilo.

ademas como te aclare al final todo depende de la que quieras hacer, una vez que esplicas tu proposito te repito que el metodo planteado por Instru es el mejor.
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 02:00.