language-design boolean-operations

language design - ¿Cómo puedo escribir como “x== 1 o 2” en un lenguaje de programación?



language-design boolean-operations (22)

Es natural, pero depende del idioma

Su enfoque parecería más natural, pero eso realmente depende del lenguaje que utilice para la implementación.

Razonamiento para el desastre

C es un lenguaje de programación de sistemas y bastante cercano al hardware (aunque es gracioso, ya que solíamos considerar un lenguaje de "alto nivel" en lugar de escribir código de máquina), no es exactamente expressive .

Los lenguajes modernos de nivel superior (de nuevo, discutible, lisp no es tan moderno, históricamente hablando, pero le permitiría hacerlo muy bien) le permiten hacer esas cosas mediante el uso de construcciones incorporadas o soporte de biblioteca (por ejemplo, usando rangos, Tuplas o equivalentes en idiomas como Python , Ruby , Groovy , ML-languages , Haskell ...).

Soluciones posibles

Opción 1

Una opción para usted sería implementar una función o subrutina tomando una matriz de valores y revisándolos.

Aquí hay un prototipo básico, y les dejo la implementación como un ejercicio:

/* returns non-zero value if check is in values */ int is_in(int check, int *values, int size);

Sin embargo, como verá rápidamente, esto es muy básico y no muy flexible:

  • funciona solo en enteros,
  • Funciona solo para comparar valores idénticos.

opcion 2

Un paso más alto en la escala de complejidad (en términos de idiomas), una alternativa sería usar macros pre-processor en C (o C++ ) para lograr un comportamiento similar, pero tenga cuidado con los efectos secundarios .

Otras opciones

Un siguiente paso podría ser pasar un puntero a una función como un parámetro adicional para definir el comportamiento en el punto de llamada, definir varias variantes y alias para esto, y construir una pequeña biblioteca de comparadores.

El siguiente paso sería implementar una cosa similar en C++ utilizando templates para hacer esto en diferentes tipos con una sola implementación.

Y luego continúe desde allí a los idiomas de nivel superior .

Elija el idioma correcto (o aprenda a dejar ir)

Normalmente, los lenguajes que favorecen la programación funcional tendrán soporte incorporado para este tipo de cosas, por razones obvias.

O simplemente aprenda a aceptar que algunos idiomas pueden hacer cosas que otros no pueden y que, dependiendo del trabajo y el entorno, así es como es. En su mayoría es azúcar sintáctica, y no hay mucho que puedas hacer. Además, algunos idiomas solucionarán sus defectos a lo largo del tiempo al actualizar sus especificaciones, mientras que otros simplemente se atascarán.

Tal vez una biblioteca ya implementa tal cosa y de la que no tengo conocimiento.

Posible duplicado:
¿Por qué la mayoría de los lenguajes de programación tienen operadores de comparación de igualdad binaria?

He tenido una pregunta simple durante bastante tiempo, desde que comencé a aprender lenguajes de programación.

Me gustaría escribir como "si x es 1 o 2 => VERDADERO (de lo contrario FALSO)".

Pero cuando lo escribo en un lenguaje de programación, digamos en C,

( x == 1 || x == 2 )

Realmente funciona pero parece incómodo y difícil de leer. Supongo que debería ser posible simplificar tal operación, y si tiene alguna idea, por favor dígamelo. Gracias nathan


¡Gracias Ignacio! Lo traduzco a Ruby:

[ 1, 2 ].include?( x )

y también funciona, pero no estoy seguro de que se vea claro y normal. Si conoces a Ruby, por favor avisa. Además, si alguien sabe cómo escribir esto en C, por favor dígamelo. Gracias. -Nathan


Cuando comencé a programar me parecía extraño que en lugar de algo como:

(1 < x < 10)

Tuve que escribir:

(1 < x && x < 10)

Pero así es como funcionan la mayoría de los lenguajes de programación, y después de un tiempo te acostumbrarás.

Así que creo que está perfectamente bien escribir.

( x == 1 || x == 2 )

Escribirlo de esta manera también tiene la ventaja de que otros programadores entenderán fácilmente lo que escribiste. Usar una función para encapsularlo podría complicar las cosas porque los otros programadores necesitarían encontrar esa función y ver qué hace.

Solo los lenguajes de programación más recientes como Python, Ruby, etc. te permiten escribirlo de una manera más simple y agradable. Esto se debe principalmente a que estos lenguajes de programación están diseñados para aumentar la productividad de los programadores, mientras que el objetivo principal de los lenguajes de programación anteriores era el rendimiento de las aplicaciones y no tanto la productividad de los programadores.


Dudo que alguna vez haga esto, pero para responder a su pregunta, aquí hay una forma de lograrlo en C # con una pequeña inferencia de tipo genérico y algún abuso de la sobrecarga del operador. Podrías escribir código como este:

if (x == Any.Of(1, 2)) { Console.WriteLine("In the set."); }

Donde la clase Any se define como:

public static class Any { public static Any2<T> Of<T>(T item1, T item2) { return new Any2<T>(item1, item2); } public struct Any2<T> { T item1; T item2; public Any2(T item1, T item2) { this.item1 = item1; this.item2 = item2; } public static bool operator ==(T item, Any2<T> set) { return item.Equals(set.item1) || item.Equals(set.item2); } // Defining the operator== requires these three methods to be defined as well: public static bool operator !=(T item, Any2<T> set) { return !(item == set); } public override bool Equals(object obj) { throw new NotImplementedException(); } public override int GetHashCode() { throw new NotImplementedException(); } } }

Any.Of podría tener una cantidad de sobrecargas del método Any.Of para trabajar con 3, 4 o incluso más argumentos. También se podrían proporcionar otros operadores, y un compañero de All clases podría hacer algo muy similar pero con && en lugar de || .

En cuanto al desmontaje, ocurre un poco de boxeo debido a la necesidad de llamar a Equals , por lo que termina siendo más lento que lo obvio (x == 1) || (x == 2) (x == 1) || (x == 2) construir. Sin embargo, si cambia todas las <T> a int y reemplaza los Equals con == , obtendrá algo que parece estar en línea muy bien para que tenga aproximadamente la misma velocidad que (x == 1) || (x == 2) (x == 1) || (x == 2) .


En .Net puedes usar Linq:

int[] wanted = new int{1, 2}; // you can use Any to return true for the first item in the list that passes bool result = wanted.Any( i => i == x ); // or use Contains bool result = wanted.Contains( x );

Aunque personalmente creo que lo básico || es lo suficientemente simple:

bool result = ( x == 1 || x == 2 );


En COBOL (ha pasado mucho tiempo desde que he echado un vistazo breve a COBOL, por lo que puedo tener un detalle o dos equivocados aquí):

IF X EQUALS 1 OR 2 ...

Así que la sintaxis es definitivamente posible. La pregunta se reduce a "¿por qué no se usa más a menudo?"

Bueno, la cosa es que analizar expresiones como esa es un poco perra. No cuando estás solo así, mente, sino más cuando estás en expresiones compuestas. La sintaxis comienza a volverse opaca (desde la perspectiva del implementador del compilador) y la semántica es muy peluda. IIRC, muchos compiladores COBOL incluso te avisarán si usas una sintaxis así debido a los posibles problemas.


En PHP puedes usar

$ret = in_array($x, array(1, 2));


En T-SQL

where x in (1,2)


En java:

List list = Arrays.asList(new Integer[]{1,2}); Set set = new HashSet(list); set.contains(1)


Err, ¿qué hay de malo en ello? Bueno, si realmente lo usas mucho y odias las apariencias, haz algo como esto en c #:

#region minimizethisandneveropen public bool either(value,x,y){ return (value == x || value == y); } #endregion

y en lugares donde lo uses:

if(either(value,1,2)) //yaddayadda

O algo así en otro idioma :).


Ni C, C ++, VB.net, C # .net, ni ningún otro lenguaje similar que conozca tienen una forma eficiente de probar si algo es una de varias opciones. Aunque (x == 1 || x == 2) es a menudo la forma más natural de codificar tal construcción, ese enfoque a veces requiere la creación de una variable temporal adicional:

tempvar = somefunction(); // tempvar only needed for ''if'' test: if (tempvar == 1 || tempvar == 2) ...

Ciertamente, un optimizador debería poder deshacerse efectivamente de la variable temporal (empujarla en un registro por el breve tiempo que se usa), pero todavía creo que el código es feo. Además, en algunos procesadores integrados, la forma más compacta y posiblemente más rápida de escribir (x == const1 || x == const2 || x == const3) es:

movf _x,w ; Load variable X into accumulator xorlw const1 ; XOR with const1 btfss STATUS,ZERO ; Skip next instruction if zero xorlw const1 ^ const2 ; XOR with (const1 ^ const2) btfss STATUS,ZERO ; Skip next instruction if zero xorlw const2 ^ const3 ; XOR with (const2 ^ const3) btfss STATUS,ZERO ; Skip next instruction if zero goto NOPE

Ese enfoque requiere dos instrucciones más para cada constante; todas las instrucciones se ejecutarán. Las pruebas de salida temprana ahorrarán tiempo si se toma la sucursal y, de lo contrario, perderán tiempo. La codificación utilizando una interpretación literal de las comparaciones separadas requeriría cuatro instrucciones para cada constante.

Si un lenguaje tuviera una construcción "si la variable es una de varias constantes", esperaría que un compilador utilice el patrón de código anterior. Lástima que no exista tal construcción en lenguajes comunes.

(Nota: Pascal tiene tal construcción, pero las implementaciones en tiempo de ejecución a menudo son un desperdicio tanto de tiempo como de espacio de código).


Pascal tiene una noción (limitada) de conjuntos, por lo que podría hacer:

if x in [1, 2] then

(No he tocado un compilador de Pascal en décadas, por lo que la sintaxis puede estar desactivada)


Perl 5 con Perl6 :: Unión :

use Perl6::Junction ''any''; say ''yes'' if 2 == any(qw/1 2 3/);

Perl 6:

say ''yes'' if 2 == 1|2|3;

Esta versión es tan legible y concisa que la usaría en lugar del || operador.


Por lo que sé, no hay una forma integrada de hacer esto en C. Podría agregar su propia función en línea para escanear una matriz de entradas para valores iguales a x ...

Al igual que:

inline int contains(int[] set, int n, int x) { int i; for(i=0; i<n; i++) if(set[i] == x) return 1; return 0; } // To implement the check, you declare the set int mySet[2] = {1,2}; // And evaluate like this: contains(mySet,2,x) // returns non-zero if ''x'' is contained in ''mySet''


Python permite probar la pertenencia a una secuencia:

if x in (1, 2):


Si bien hay una serie de respuestas bastante interesantes en este hilo, me gustaría señalar que pueden tener implicaciones en el rendimiento si está haciendo este tipo de lógica dentro de un bucle, dependiendo del idioma. Desde el punto de vista de la computadora, el if (x == 1 || x == 2) es, con mucho, el más fácil de entender y optimizar cuando se compila en el código de máquina.


Tengo una macro que utilizo mucho que es algo similar a lo que quieres.

#define ISBETWEEN(Var, Low, High) ((Var) >= (Low) && (Var) <= (High))

ISBETWEEN(x, 1, 2) devolverá verdadero si x es 1 o 2.


Un intento con un solo operador booleano no bit a bit (no se recomienda, no se ha probado):

if( (x&3) ^ x ^ ((x>>1)&1) ^ (x&1) ^ 1 == 0 )

La parte (x&3) ^ x debe ser igual a 0, esto asegura que x esté entre 0 y 3. Otros operandos solo tendrán el último bit establecido.

La ((x>>1)&1) ^ (x&1) ^ 1 parte asegura que el último y segundo a último bit son diferentes. Esto se aplicará a 1 y 2, pero no a 0 y 3.


Una versión de extensión en C #

paso 1: crear un método de extensión

public static class ObjectExtensions { public static bool Either(this object value, params object[] array) { return array.Any(p => Equals(value, p)); } }

paso 2: usa el método de extensión

if (x.Either(1,2,3,4,5,6)) { } else { }


Usted dice que la notación (x==1 || x==2) es "torpe y difícil de leer". Siento disentir. Es diferente al lenguaje natural, pero es muy claro y fácil de entender. Solo necesitas pensar como una computadora.

Además, las notaciones mencionadas en este hilo como x in (1,2) son semánticamente diferentes de lo que realmente estás preguntando, preguntan si x es miembro del conjunto (1,2) , que no es lo que estás preguntando. Lo que está preguntando es if x equals to 1 or to 2 que es lógicamente (y semánticamente) equivalente a if x equals to 1 or x equals to 2 que se traduce a (x==1 || x==2) .


devuelve x === 1 || x === 2 en javascript


eso fue un montón de alternativas interesantes. Me sorprende que nadie mencione el interruptor ... caso - así que aquí va:

switch(x) { case 1: case 2: // do your work break; default: // the else part }

  1. es más legible que tener un montón de x == 1 || x == 2 || ...
  2. más óptimo que tener una matriz / conjunto / lista para hacer una verificación de membresía