Operadores booleanos && y ||

252

De acuerdo con la definición del lenguaje R , la diferencia entre &y &&(correspondientemente |y ||) es que el primero está vectorizado mientras que el segundo no.

De acuerdo con el texto de ayuda , leí la diferencia similar a la diferencia entre un "Y" y "AndAlso" (correspondientemente "O" y "O Else") ... Significado: Que no todas las evaluaciones si no tienen que ser (es decir, A, B o C siempre es cierto si A es verdadero, así que deje de evaluar si A es verdadero)

¿Alguien podría arrojar luz aquí? Además, ¿hay un AndAlso y OrElse en R?

SFun28
fuente
Consulte también preguntas similares en stackoverflow.com/q/6933598/210673 y stackoverflow.com/q/7953833/210673 (ahora cerrado como duplicado).
Aaron dejó Stack Overflow el
3
Creo que && y || están mal implementados en R. En otros idiomas son operadores condicionales AND y OR, realizan operaciones lógicas AND u OR booleanas, pero solo evalúan su segundo operando si es necesario. En R no hagas nada útil.
skan

Respuestas:

340

Los más cortos están vectorizados, lo que significa que pueden devolver un vector, como este:

((-2:2) >= 0) & ((-2:2) <= 0)
# [1] FALSE FALSE  TRUE FALSE FALSE

La forma más larga evalúa de izquierda a derecha examinando solo el primer elemento de cada vector, por lo que lo anterior da

((-2:2) >= 0) && ((-2:2) <= 0)
# [1] FALSE

Como dice la página de ayuda, esto hace que la forma más larga "sea apropiada para programar el flujo de control y [es] típicamente preferida en las cláusulas if".

Por lo tanto, desea utilizar las formas largas solo cuando esté seguro de que los vectores son de longitud uno.

Debe estar absolutamente seguro de que sus vectores son solo longitud 1, como en los casos en que son funciones que devuelven solo booleanos de longitud 1. Desea usar las formas cortas si los vectores son de longitud posiblemente> 1. Entonces, si no está absolutamente seguro, debe verificar primero o usar el formulario corto y luego usar ally anyreducirlo a la longitud uno para usar en declaraciones de flujo de control, como if.

Las funciones ally anyse utilizan a menudo en el resultado de una comparación vectorizada para ver si todas o alguna de las comparaciones son verdaderas, respectivamente. Los resultados de estas funciones seguramente serán de longitud 1, por lo que son apropiados para su uso en cláusulas if, mientras que los resultados de la comparación vectorizada no lo son. (Aunque esos resultados serían apropiados para usar en ifelse.

Una diferencia final: el &&y ||solo evalúa tantos términos como sea necesario (que parece ser lo que se entiende por cortocircuito). Por ejemplo, aquí hay una comparación usando un valor indefinido a; si no hiciera un cortocircuito, como &y |no, daría un error.

a
# Error: object 'a' not found
TRUE || a
# [1] TRUE
FALSE && a
# [1] FALSE
TRUE | a
# Error: object 'a' not found
FALSE & a
# Error: object 'a' not found

Finalmente, vea la sección 8.2.17 en The R Inferno , titulada "and and andand".

Aaron dejó Stack Overflow
fuente
Estoy comparando lógicas de longitud 1. La documentación no es clara sobre por qué es preferible para el flujo de control. ¿Es porque usa el "cortocircuito" de las respuestas de @ Theo y, por lo tanto, tiene un mejor rendimiento?
SFun28
no Simplemente use la forma corta '&': las respuestas de cortocircuito son incorrectas.
M. Tibbits
1
No, porque garantiza tener una sola respuesta VERDADERO / FALSO. Las formas más cortas podrían resultar c(TRUE, FALSE), y la ifdeclaración no sería clara. Si está seguro de que todo tiene longitud 1, entonces sí, cualquiera de los dos lo haría, y tiene razón en que el "cortocircuito" es la razón para preferir uno. Sin embargo, una advertencia: asegúrese de estar 100% seguro de que solo pueden ser de longitud uno. De lo contrario, puede obtener errores realmente tontos.
Aaron dejó Stack Overflow el
99
@ SFun28: Sí, el cortocircuito es la razón por la que prefiere el control de flujo. Además de un mejor rendimiento, es posible que no desee evaluar todos los argumentos. El ejemplo canónico se da ?is.Rpara verificar si está ejecutando R o S-Plus. if(exists("is.R") && is.function(is.R) && is.R()). Si is.Rno existe, entonces no desea evaluar is.function(is.R)ya que arrojará un error. Del mismo modo, si is.Rno es una función, no desea llamarla como si lo fuera.
Richie Cotton
2
En la versión actual del infierno R, la sección relevante ahora es 8.2.17 "yy andand"
Silverfish
34

La respuesta sobre "cortocircuito" es potencialmente engañosa, pero tiene algo de verdad (ver más abajo). En el lenguaje R / S, &&y ||solo evalúa el primer elemento en el primer argumento. Todos los demás elementos en un vector o lista se ignoran independientemente del valor de los primeros. Esos operadores están diseñados para trabajar con la if (cond) {} else{}construcción y dirigir el control del programa en lugar de construir nuevos vectores. El &y los |operadores están diseñados para trabajar en vectores, por lo que se aplicarán "en paralelo", por así decirlo, a lo largo de El argumento más largo. Ambos vectores deben evaluarse antes de hacer las comparaciones. Si los vectores no tienen la misma longitud, se realiza el reciclaje del argumento más corto.

Cuando se evalúan los argumentos &&o ||se evalúa, existe un "cortocircuito" en el sentido de que si alguno de los valores sucesivos de izquierda a derecha es determinante, las evaluaciones cesan y se devuelve el valor final.

> if( print(1) ) {print(2)} else {print(3)}
[1] 1
[1] 2
> if(FALSE && print(1) ) {print(2)} else {print(3)} # `print(1)` not evaluated
[1] 3
> if(TRUE && print(1) ) {print(2)} else {print(3)}
[1] 1
[1] 2
> if(TRUE && !print(1) ) {print(2)} else {print(3)}
[1] 1
[1] 3
> if(FALSE && !print(1) ) {print(2)} else {print(3)}
[1] 3

La ventaja del cortocircuito solo aparecerá cuando los argumentos tarden mucho en evaluarse. Esto ocurrirá típicamente cuando los argumentos son funciones que procesan objetos más grandes o tienen operaciones matemáticas que son más complejas.

IRTFM
fuente
"cortocircuito" es un término nuevo para mí, pero me parece que la respuesta que lo describe está de acuerdo con lo que usted dice &&y ||.
Aaron dejó Stack Overflow el
@DWin: en el caso de operar con lógica de longitud 1, son equivalentes, ¿verdad? Estoy tratando de entender por qué son preferidos en el flujo de control como dice la documentación. Además, ¿tiene R una construcción de "cortocircuito"?
SFun28
NO son equivalentes para vectores de longitud> 1
M. Tibbits
2
Es cierto que si los argumentos para &&son funciones y el primero es falso, entonces el segundo no será evaluado. Eso no es cierto para ninguno &o ifelseque evaluará ambos argumentos.
IRTFM
¿No es eso lo que dice también la respuesta de Theo sobre los cortocircuitos?
Aaron dejó Stack Overflow el
25

&&y ||son lo que se llama "cortocircuito". Eso significa que no evaluarán el segundo operando si el primer operando es suficiente para determinar el valor de la expresión.

Por ejemplo, si el primer operando a &&es falso, entonces no tiene sentido evaluar el segundo operando, ya que no puede cambiar el valor de la expresión ( false && truey false && falseambos son falsos). Lo mismo ocurre ||cuando el primer operando es verdadero.

Puede leer más sobre esto aquí: http://en.wikipedia.org/wiki/Short-circuit_evaluation En la tabla de esa página puede ver que &&es equivalente a AndAlsoVB.NET, al que supongo que se refiere.

Theo
fuente
3
Esto debería ser suficiente prueba de que es un cortocircuito: f <- function() { print('hello'); TRUE }; FALSE && f(). Cambie &y observe que se evalúa la función. QED
Theo
2
Theo, sí, tienes razón &&y ||cortocircuito. Pero ese es realmente un punto bastante menor en las comparaciones entre la forma corta y la forma larga; Es mucho más importante comprender qué hace cada uno cuando las entradas son vectores.
Aaron dejó Stack Overflow el
2
@MTibbits De hecho, esta no es una respuesta completa, pero la afirmación sobre cortocircuito es correcta . Pruebe F & {message("Boo!");T}y F && {message("Boo!");T}.
mbq