Operadores booleanos && e ||

252

De acordo com a definição da linguagem R , a diferença entre &e &&(correspondentemente |e ||) é que o primeiro é vetorizado enquanto o último não.

De acordo com o texto de ajuda , li a diferença semelhante à diferença entre um "E" e "AndAlso" (correspondentemente "Or" e "OrElse") ... Significado: Que nem todas as avaliações, se não tiverem que ser (ou seja, A ou B ou C sempre é verdadeiro se A for verdadeiro, pare de avaliar se A é verdadeiro)

Alguém poderia lançar luz aqui? Além disso, existe um AndAlso e OrElse em R?

SFun28
fonte
Consulte também perguntas semelhantes em stackoverflow.com/q/6933598/210673 e stackoverflow.com/q/7953833/210673 (agora fechado como duplicado).
Aaron deixou Stack Overflow
3
Eu acho que&& e || são mal implementados em R. Em outros idiomas, os operadores condicionais AND e OR realizam operações booleanas lógicas AND ou OR, mas apenas avaliam seu segundo operando, se necessário. Em R não faça nada útil.
Skan28 Nov16

Respostas:

340

Os mais curtos são vetorizados, o que significa que eles podem retornar um vetor, assim:

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

A forma mais longa avalia da esquerda para a direita, examinando apenas o primeiro elemento de cada vetor;

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

Como a página de ajuda diz, isso torna a forma mais longa "apropriada para programar o fluxo de controle e [é] normalmente preferida nas cláusulas if".

Portanto, você deseja usar as formas longas apenas quando tiver certeza de que os vetores têm o comprimento um.

Você deve ter certeza absoluta de que seus vetores têm apenas o comprimento 1, como nos casos em que são funções que retornam apenas o comprimento 1 dos booleanos. Você deseja usar os formulários curtos se os vetores tiverem comprimento> possivelmente 1. Portanto, se você não tiver certeza absoluta, verifique primeiro ou use o formulário curto e, em seguida, use-o alle anyreduza-o ao comprimento um para uso em instruções de fluxo de controle, como if.

As funções alle anysão frequentemente usadas no resultado de uma comparação vetorizada para verificar se todas ou quaisquer comparações são verdadeiras, respectivamente. Os resultados dessas funções certamente têm o comprimento 1, portanto são apropriados para uso nas cláusulas if, enquanto os resultados da comparação vetorizada não são. (Embora esses resultados sejam apropriados para uso no ifelse.

Uma diferença final: o &&e ||avaliar apenas quantos termos forem necessários (o que parece ser o que se entende por curto-circuito). Por exemplo, aqui está uma comparação usando um valor indefinido a; se não curto-circuito, como &e |não, daria um erro.

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

Por fim, consulte a seção 8.2.17 no The R Inferno , intitulada "and and andand".

Aaron deixou Stack Overflow
fonte
Estou comparando as lógicas de comprimento 1. A documentação não está clara sobre por que é preferida para o fluxo de controle. Isso ocorre porque ele usa o "curto-circuito" das respostas de @ Theo e, portanto, tem melhor desempenho?
SFun28
Não. Basta usar o formulário curto '&' - as respostas de curto-circuito estão incorretas.
M. Tibbits
1
Não, porque garante ter apenas uma única resposta VERDADEIRA / FALSA. As formas mais curtas podem resultar c(TRUE, FALSE), e a ifdeclaração não seria clara. Se você tem certeza de que tudo tem o comprimento 1, então sim, qualquer um faria, e você está certo de que o "curto-circuito" é a razão para a sua preferência. Uma palavra de aviso, porém, verifique se você tem 100% de certeza de que eles podem ter apenas o comprimento um. Caso contrário, você pode obter bugs realmente patetas.
Aaron deixou Stack Overflow em
9
@ SFun28: Sim, o curto-circuito é o motivo preferido para o controle de fluxo. Além do melhor desempenho, você pode não querer avaliar todos os argumentos. O exemplo canônico é fornecido ?is.Rpara verificar se você está executando o R ou S-Plus. if(exists("is.R") && is.function(is.R) && is.R()). Se is.Rnão existir, você não deseja avaliar, is.function(is.R)pois isso gera um erro. Da mesma forma, se is.Rnão for uma função, você não deseja chamá-la como se fosse.
Richie Cotton
2
Na versão atual do R inferno, a seção relevante é agora 8.2.17 "and andand"
Silverfish 7/14
34

A resposta sobre "curto-circuito" é potencialmente enganosa, mas tem alguma verdade (veja abaixo). No R / S linguagem, &&e ||só avaliam o primeiro elemento no primeiro argumento. Todos os outros elementos em um vetor ou lista são ignorados, independentemente do valor inicial. Esses operadores são projetados para trabalhar com a if (cond) {} else{}construção e para o controle do programa direta, em vez de construir novos vetores .. O &e os |operadores são projetados para trabalhar em vetores, então eles vão ser aplicadas "em paralelo", por assim dizer, ao longo do comprimento o argumento mais longo. Ambos os vetores precisam ser avaliados antes que as comparações sejam feitas. Se os vetores não tiverem o mesmo comprimento, será realizada a reciclagem do argumento mais curto.

Quando os argumentos para &&ou ||são avaliados, há "curto-circuito", pois se algum dos valores sucessivos da esquerda para a direita for determinante, as avaliações cessarão e o valor final será retornado.

> 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

A vantagem do curto-circuito só aparecerá quando os argumentos levarem muito tempo para serem avaliados. Isso geralmente ocorre quando os argumentos são funções que processam objetos maiores ou têm operações matemáticas mais complexas.

IRTFM
fonte
"curto-circuito" é um novo termo para mim, mas me parece que a resposta que o descreve concorda com o que você diz sobre &&e ||.
Aaron saiu de Stack Overflow em
@DWin - no caso de operar com lógicas de comprimento 1, elas são equivalentes, certo? Estou tentando entender por que eles são preferidos no fluxo de controle como a documentação declara. Além disso, R tem uma construção de "curto-circuito"?
SFun28
Eles são NÃO equivalente para vetores de tamanho> 1
M. Tibbits
2
É verdade que, se os argumentos to &&são funções e o primeiro for falso, o segundo não será avaliado. Isso não é verdade para um &ou para o ifelsequal avaliará os dois argumentos.
IRTFM 02/07
Não é isso que a resposta de Theo sobre curto-circuito também diz?
Aaron saiu de Stack Overflow em
25

&&e ||são o que é chamado de "curto-circuito". Isso significa que eles não avaliarão o segundo operando se o primeiro for suficiente para determinar o valor da expressão.

Por exemplo, se o primeiro operando para &&for falso, não há sentido em avaliar o segundo operando, pois ele não pode alterar o valor da expressão ( false && truee false && falseambos são falsos). O mesmo vale para ||quando o primeiro operando for verdadeiro.

Você pode ler mais sobre isso aqui: http://en.wikipedia.org/wiki/Short-circuit_evaluation Na tabela dessa página, você pode ver que isso &&é equivalente ao AndAlsoVB.NET, ao qual suponho que você esteja se referindo.

Theo
fonte
3
Isso deve ser suficiente prova de que é curto-circuito: f <- function() { print('hello'); TRUE }; FALSE && f(). Mude para &e observe que a função é avaliada. QED.
Theo
2
Theo, sim, você está correto &&e está em ||curto-circuito. Mas esse é realmente um ponto bastante menor nas comparações entre a forma curta e a forma longa; é muito mais importante entender o que cada um faz quando as entradas são vetores.
Aaron deixou o Stack Overflow em
2
@MTibbits De fato, essa não é uma resposta completa, mas a declaração sobre curtos-circuitos está correta . Tente F & {message("Boo!");T}e F && {message("Boo!");T}.
MBq