Tengo un código que tiene una secuencia de if
s que funciona, pero me siento desordenado. Básicamente, quiero elegir el mayor de tres enteros y establecer una bandera de estado para decir cuál fue elegido. Mi código actual se ve así:
a = countAs();
b = countBs();
c = countCs();
if (a > b && a > c)
status = MOSTLY_A;
else if (b > a && b > c)
status = MOSTLY_B;
else if (c > a && c > b)
status = MOSTLY_C;
else
status = DONT_KNOW;
Este patrón ocurre algunas veces, y con nombres largos de variables se hace un poco difícil confirmar visualmente que cada uno if
es correcto. Siento que podría haber una manera mejor y más clara de hacer esto; ¿Alguien puede sugerir algo?
Hay algunos posibles duplicados, pero no se alinean con esta pregunta.
En el duplicado sugerido: ¿ Enfoques para verificar múltiples condiciones? Todas las soluciones sugeridas parecen igualmente torpes como el código original, por lo que no proporcionan una solución mejor.
Y esta publicación Formas elegantes de manejar si (si no) más se ocupa solo de los niveles de anidación y la asimetría, que no es el problema aquí.
fuente
Respuestas:
Factoriza la lógica, regresa temprano
Como se sugiere en los comentarios, sería suficiente simplemente envolver su lógica en una función y salir temprano con
return
's' para simplificar mucho las cosas. Además, puede factorizar un poco de funcionalidad al delegar las pruebas a otra función. Más concretamente:Esto es más corto que mi intento anterior:
Lo anterior es un poco más detallado, pero es fácil de leer en mi humilde opinión y no vuelve a calcular las comparaciones varias veces.
Confirmación visual
En tu respuesta dices:
... también, en tu pregunta, dices:
Es posible que no entienda lo que está tratando de lograr: ¿desea copiar y pegar el patrón donde lo necesite? Con una función como la anterior, captura el patrón una vez, y verifica una vez todo lo que usan todas las comparaciones
a
,b
yc
según sea necesario. Entonces, no necesita preocuparse más cuando llama a la función. Por supuesto, tal vez en la práctica su problema sea un poco más complejo que el que describió: si es así, agregue algunos detalles si es posible.fuente
MOSTLY_A
oMOSTLY_C
en el casoa == c
ya > b
. Esto está arreglado. Gracias.TL: DR; Su código ya es correcto y "limpio".
Veo a muchas personas preguntándose por la respuesta, pero a todos les falta el bosque a través de los árboles. Hagamos la informática completa y el análisis matemático para comprender completamente esta pregunta.
Primero, notamos que tenemos 3 variables, cada una con 3 estados: <, = o>. El número total de permutaciones es 3 ^ 3 = 27 estados, a los que asignaré un número único, denotado P #, para cada estado. Este número P # es un sistema de números factoriales .
Enumerando todas las permutaciones que tenemos:
Por inspección vemos que tenemos:
Escribamos un programa (vea la nota al pie) para enumerar todas estas permutaciones con valores para A, B y C. Clasificación estable por P #:
En caso de que te estés preguntando cómo sabía qué estados P # eran imposibles, ahora lo sabes. :-)
El número mínimo de comparaciones para determinar el orden es:
Log2 (27) = Log (27) / Log (2) = ~ 4.75 = 5 comparaciones
es decir, coredump dio el número mínimo correcto de 5 comparaciones. Daría formato a su código como:
Para su problema, no nos interesan las pruebas de igualdad, por lo que podemos omitir 2 pruebas.
¡No importa cuán limpio / malo sea el código si obtiene la respuesta incorrecta, por lo que es una buena señal de que está manejando todos los casos correctamente!
Luego, en lo que respecta a la simplicidad, las personas siguen tratando de "mejorar" la respuesta, donde piensan que mejorar significa "optimizar" el número de comparaciones, pero eso no es estrictamente lo que usted pregunta. Confundiste a todos cuando preguntaste "Siento que podría haber un mejor" pero no definiste qué significa "mejor". Menos comparaciones? ¿Menos código? ¿Comparaciones óptimas?
Ahora, ya que está preguntando sobre la legibilidad del código (dada la corrección), solo haría un cambio en su código para la legibilidad: alinee la primera prueba con las otras.
Personalmente, lo escribiría de la siguiente manera, pero esto puede ser demasiado poco ortodoxo para sus estándares de codificación:
Nota al pie: Aquí está el código C ++ para generar las permutaciones:
Ediciones: Basado en comentarios, movió TL: DR a la parte superior, eliminó la tabla sin clasificar, aclaró 27, limpió el código, describió los estados imposibles.
fuente
@msw le dijo que usara una matriz en lugar de a, b, c, y @Basile le dijo que refactorizara la lógica "max" en una función. La combinación de estas dos ideas conduce a
luego proporcione una función que calcule el índice máximo de una matriz arbitraria:
y llámalo como
El número total de LOC parece haber aumentado sobre el original, pero ahora tiene la lógica central en una función reutilizable, y si puede reutilizar la función varias veces, comienza a dar sus frutos. Además, la
FindStrictMaxIndex
función ya no está entretejida con sus "requisitos comerciales" (separación de preocupaciones), por lo tanto, el riesgo que tendrá que modificar más adelante es mucho menor que en su versión original (principio abierto-cerrado). Por ejemplo, esa función no tendrá que cambiarse incluso si cambia el número de argumentos, o si necesita usar otros valores de retorno que MOSTLY_ABC, o si está procesando otras variables que no sean a, b, c. Además, el uso de una matriz en lugar de 3 valores diferentes a, b, c también podría simplificar su código en otros lugares.Por supuesto, si en todo su programa solo hay uno o dos lugares para llamar a esta función, y no tiene más aplicaciones para mantener los valores en una matriz, entonces probablemente dejaría el código original como está (o use @ mejora de coredump).
fuente
FindStrictMaxIndex()
pueden no estar demasiado limpias, pero desde el punto de vista de la persona que llama es bastante obvio lo que se está tratando de lograr.int
función escrita. Pero acepto su comentario si uno usa un lenguaje diferente como Python o Perl.FindStrictMaxIndex
se puede reutilizar la función. Por una o solo dos veces de reutilización, esto no valdrá la pena, por supuesto, pero eso es lo que ya escribí en mi respuesta. Tenga en cuenta también las otras ventajas que mencioné anteriormente con respecto a los cambios futuros.return result[FindStrictMaxIndex(val,3)];
en el punto del código donde se colocaron las 8 líneas originales . Las otras partes, especialmente enFindStrictMaxIndex
sí mismas, están completamente separadas de la "lógica empresarial", que las saca del foco de los requisitos comerciales cambiantes.Probablemente deberías usar una macro o una función que
MAX
dé el máximo de dos números.Entonces solo quieres:
Es posible que hayas definido
pero tenga cuidado, notablemente sobre los efectos secundarios, cuando use macros (ya que
MAX(i++,j--)
se comportaría de manera extraña)Así que mejor define una función
y úsalo (o al menos
#define MAX(X,Y) max2ints((X),(Y))
...)Si necesita comprender el origen del MAX, es posible que tenga una macro larga como la
#define COMPUTE_MAX_WITH_CAUSE(Status,Result,X,Y,Z)
que es largado{
...}while(0)
macro, tal vezEntonces podrías invocar
COMPUTE_MAX_WITH_CAUSE(status,res,a,b,c)
en varios lugares. Es un poco feo. He definido las variables localesx
,y
,z
para reducir los efectos secundarios malos ....fuente
He pensado más sobre esto, así que dado que mi problema era principalmente la confirmación visual de que todas las comparaciones usaban las mismas variables, creo que este podría ser un enfoque útil:
Que cada macro toma
a
,b
yc
en el mismo orden es fácil de confirmar, y el nombre de la macro me ahorra tener que averiguar qué están haciendo todas las comparaciones y AND.fuente