¿Cómo puedo hacer esto con elegancia con C # y .NET 3.5 / 4?
Por ejemplo, un número puede estar entre 1 y 100.
Sé que un simple si sería suficiente; pero la palabra clave para esta pregunta es elegancia. Es para mi proyecto de juguete, no para producción.
Estas preguntas no se referían a la velocidad, sino a la belleza del código. Deja de hablar de eficiencia y tal; recuerda que estás predicando al coro.
if
no es "barroco", no lo arregles.Respuestas:
Hay muchas opciones:
Además, consulte esta publicación SO para ver las opciones de expresiones regulares.
fuente
if
declaración. Esto ciertamente logra que ...;)¿Quieres decir?
o
fuente
Solo para agregar al ruido aquí, podría crear un método de extensión:
Lo que te permitiría hacer algo como ...
Dicho esto, esto parece una tontería cuando el cheque en sí es solo una línea.
fuente
Como otros dijeron, use un simple if.
Debes pensar en el pedido.
p.ej
es más fácil de leer que
fuente
1 <= x <= 100
.=
lugar de==
. No ayuda con los operadores relacionales que no son de igualdad, pero es fácil acostumbrarse a usarlo de manera consistente.x
es una llamada de función compleja o una expresión de Linq que consume mucho tiempo. En este caso, harías esto dos veces, lo que no es bueno. Claro que debe almacenar el valor en una variable local temporal, pero hay algunos casos (por ejemplo, en sentencias else-if) en los que solo desea llamar a las funciones después de que otros if's o else-if hayan fallado. Con las variables temporales, debe llamarlas de todos modos antes. Un método de extensión (mencionado en otras respuestas) es la mejor solución en mi caso.En el código de producción simplemente escribiría
Esto es fácil de entender y muy legible.
Aquí hay un método inteligente que reduce el número de comparaciones de dos a uno mediante el uso de algunas matemáticas. La idea es que uno de los dos factores se vuelve negativo si el número se encuentra fuera del rango y cero si el número es igual a uno de los límites:
Si los límites son inclusivos:
o
Si los límites son exclusivos:
o
fuente
1 < x && x < 100
código simple y productivo. Es más fácil de entender.1 < x & x < 100
(no && short circuit) le indica al compilador que siempre puede evaluarx < 100
sin importar el resultado1 < x
. Curiosamente (debido a la predicción de ramificación) es más rápido hacer siempre esta operación simple que a veces omitirla.Propongo esto:
Ejemplos:
y por supuesto con variables:
Es fácil de leer (cercano al lenguaje humano) y funciona con cualquier tipo comparable (entero, doble, tipos personalizados ...).
Tener un código fácil de leer es importante porque el desarrollador no desperdiciará "ciclos cerebrales" para comprenderlo. En largas sesiones de codificación, los ciclos cerebrales desperdiciados hacen que el desarrollador se canse antes y sea propenso a errores.
fuente
IsInRange. I'm not that keen on Ben's inclusive boolean as that requires a few more brain cycles. It has the advantage that it can be used in any class that that implements IComparer. This is in my Extensions now along with
LiesWithin /LiesInside. Just can't decide which.
NotOutside funcionaría pero no me gustan las condiciones negativasCon un poco de abuso del método de extensión, podemos obtener la siguiente solución "elegante":
fuente
enum Inclusive
con los valores:Lower
,Upper
,All
. Y pasar a laIn
función de un parámetro adicional de tipoenum Inclusive
con el valor predeterminadoInclusive.All
, actualizar elTo
cuerpo de la función de asaAll
,Lower
,Upper
valores :)Si esto es incidental, un simple
if
es todo lo que necesita. Si esto sucede en muchos lugares, es posible que desee considerar estos dos:Algo como:
fuente
fuente
Usar una
&&
expresión para unir dos comparaciones es simplemente la forma más elegante de hacerlo. Si intenta utilizar métodos de extensión sofisticados y demás, se encontrará con la pregunta de si incluir el límite superior, el límite inferior o ambos. Una vez que comience a agregar variables adicionales o cambie los nombres de las extensiones para indicar qué está incluido, su código se vuelve más largo y difícil de leer (para la gran mayoría de los programadores). Además, herramientas como Resharper te avisarán si tu comparación no tiene sentido (number > 100 && number < 1
), lo que no harán si utiliza un método ('i.IsBetween (100, 1)').El único otro comentario que haría es que si está verificando entradas con la intención de lanzar una excepción, debería considerar usar contratos de código:
Esto es más elegante que
if(...) throw new Exception(...)
, e incluso podría obtener advertencias en tiempo de compilación si alguien intenta llamar a su método sin asegurarse de que el número esté dentro de los límites primero.fuente
Si desea escribir más código que un simple if, tal vez pueda: Crear un Método de extensión llamado IsBetween
...
Apéndice:Vale la pena señalar que en la práctica rara vez "simplemente verifica la igualdad" (o <,>) en una base de código. (Aparte de en las situaciones más triviales). Simplemente como ejemplo, cualquier programador de juegos usaría categorías como las siguientes en cada proyecto, como una cuestión básica. Tenga en cuenta que en este ejemplo (resulta ser) que usa una función (Mathf. Aproximadamente) que está integrada en ese entorno; En la práctica, normalmente tiene que desarrollar cuidadosamente sus propios conceptos de lo que significan las comparaciones para las representaciones de números reales por computadora, para el tipo de situación que está diseñando. (Ni siquiera mencione que si está haciendo algo como, tal vez un controlador, un controlador PID o similar, todo el problema se vuelve central y muy difícil, se convierte en la naturaleza del proyecto.
fuente
return (value >= Min && value <= Max);
Porque todas las otras respuestas no las inventé yo, aquí solo mi implementación:
Luego puede usarlo así:
fuente
EDITAR: Nueva respuesta proporcionada. Estaba comenzando a usar C # cuando escribí la primera respuesta a esta pregunta, y en retrospectiva ahora me doy cuenta de que mi "solución" era / es ingenua e ineficiente.
Mi respuesta original: iría con la versión más simple:
if(Enumerable.Range(1,100).Contains(intInQuestion)) { ...DoStuff; }
Una mejor manera
Como no he visto ninguna otra solución que sea más eficiente (al menos según mis pruebas), lo intentaré de nuevo.
Nueva y mejor manera que también funciona con rangos negativos :
Esto se puede usar con rangos positivos y negativos y los valores predeterminados para un rango de
1..100 (inclusive) y se utiliza
x
como número para verificar seguido de un rango opcional definido pormin
ymax
.Agregar ejemplos de buena medida
Ejemplo 1:
Devoluciones:
Ejemplo 2: uso de una lista de entradas aleatorias entre 1 y 150
Devoluciones:
Tiempo de ejecución: 0.016 segundo (s)
fuente
Un nuevo giro en un viejo favorito:
fuente
En C, si la eficiencia del tiempo es crucial y se desbordan los desbordamientos de enteros, se podría hacer
if ((unsigned)(value-min) <= (max-min)) ...
. Si 'max' y 'min' son variables independientes, la resta adicional para (max-min) perderá tiempo, pero si esa expresión puede calcularse previamente en tiempo de compilación, o si puede calcularse una vez en tiempo de ejecución para probar muchas números contra el mismo rango, la expresión anterior se puede calcular de manera eficiente incluso en el caso de que el valor esté dentro del rango (si una gran fracción de valores estará por debajo del rango válido, puede ser más rápido de usarif ((value >= min) && (value <= max)) ...
porque saldrá temprano si el valor es menos de min).Sin embargo, antes de usar una implementación como esa, evalúe la máquina de destino de uno. En algunos procesadores, la expresión de dos partes puede ser más rápida en todos los casos ya que las dos comparaciones se pueden hacer de forma independiente, mientras que en el método de restar y comparar la resta tiene que completarse antes de que la comparación pueda ejecutarse.
fuente
¿Qué tal algo como esto?
con el método de extensión de la siguiente manera (probado):
fuente
Haría un objeto Range, algo como esto:
Luego lo usas de esta manera:
De esa manera puedes reutilizarlo para otro tipo.
fuente
Range
objeto necesita usar elCompareTo
método para comparar elementos, no el<
operador.IComparable
y no sobrecargue al<
operador.Al verificar si un "Número" está en un rango, debe ser claro en lo que quiere decir, y ¿qué significan dos números iguales? En general, debe envolver todos los números de coma flotante en lo que se llama una 'bola épsilon'. Esto se hace seleccionando un valor pequeño y diciendo que si dos valores están tan cerca, son lo mismo.
Con estos dos ayudantes en su lugar y suponiendo que si algún número se puede lanzar como doble sin la precisión requerida. Todo lo que necesitará ahora es una enumeración y otro método
El otro método sigue:
Ahora, esto puede ser mucho más de lo que quería, pero le impide tratar de redondear todo el tiempo y tratar de recordar si un valor se ha redondeado y a qué lugar. Si lo necesita, puede extenderlo fácilmente para trabajar con cualquier épsilon y permitir que su épsilon cambie.
fuente
Uso
double numberToBeChecked = 7;
resultado var = numberToBeChecked.IsBetween (100,122);
resultado var = 5.IsBetween (100,120);
resultado var = 8.0.IsBetween (1.2,9.6);
fuente
Si le preocupa el comentario de @Daap sobre la respuesta aceptada y solo puede pasar el valor una vez, puede intentar uno de los siguientes
o
fuente
En cuanto a la elegancia, lo más parecido a la notación matemática ( a <= x <= b ) mejora ligeramente la legibilidad:
Para más ilustración:
fuente
Estaba buscando una manera elegante de hacerlo donde los límites podrían cambiarse (es decir, no estoy seguro en qué orden están los valores).
Esto solo funcionará en versiones más nuevas de C # donde el?: Existe
Obviamente, podría cambiar los signos = allí para sus propósitos. Podría ser elegante con el tipo de casting también. Solo necesitaba un retorno flotante dentro de los límites (o igual a)
fuente
Elegante porque no requiere que determine cuál de los dos valores límite es mayor primero. Tampoco contiene ramas.
fuente
No lo sé pero uso este método:
Y esta es la forma en que puedo usarlo:
fuente
Estos son algunos métodos de extensión que pueden ayudar
fuente
Si se trata de validar los parámetros del método, ninguna de las soluciones arroja ArgumentOutOfRangeException y permite una configuración fácil / adecuada de valores min / max inclusivos / exclusivos.
Usar así
Acabo de escribir estas hermosas funciones. También tiene la ventaja de no tener ramificaciones (un solo if) para valores válidos. La parte más difícil es crear los mensajes de excepción adecuados.
fuente
Que estas buscando
in [1..100]
? Eso es solo Pascal.fuente
when (number) { in 0..9 -> println("1 digit") in 10..99 -> println("2 digits") in 100..999 -> println("3 digits") }