Opérateurs booléens && et ||

252

Selon la définition du langage R , la différence entre &et &&(en conséquence |et ||) est que le premier est vectorisé alors que le second ne l'est pas.

Selon le texte d'aide , j'ai lu la différence semblable à la différence entre un "Et" et "AndAlso" (correspondant "Ou" et "OrElse") ... Signification: Ce ne sont pas toutes les évaluations si elles ne doivent pas être (c'est-à-dire que A ou B ou C est toujours vrai si A est vrai, alors arrêtez d'évaluer si A est vrai)

Quelqu'un pourrait-il faire la lumière ici? Y a-t-il également un AndAlso et un OrElse dans R?

SFun28
la source
Voir également des questions similaires sur stackoverflow.com/q/6933598/210673 et stackoverflow.com/q/7953833/210673 (désormais fermé en double).
Aaron a quitté Stack Overflow
3
Je pense que && et || sont mal implémentés en R. Dans d'autres langages ce sont les opérateurs conditionnels ET et OU, ils effectuent une opération booléenne logique OU ou OU, mais n'évaluent son deuxième opérande que si nécessaire. Dans R, ne faites rien d'utile.
skan

Réponses:

340

Les plus courts sont vectorisés, ce qui signifie qu'ils peuvent renvoyer un vecteur, comme ceci:

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

Le formulaire plus long évalue de gauche à droite en examinant uniquement le premier élément de chaque vecteur, donc ce qui précède donne

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

Comme l'indique la page d'aide, cela rend le formulaire plus long "approprié pour la programmation du flux de contrôle et [est] généralement préféré dans les clauses if".

Vous souhaitez donc utiliser les formes longues uniquement lorsque vous êtes certain que les vecteurs sont de longueur un.

Vous devez être absolument certain que vos vecteurs ne sont que de longueur 1, comme dans le cas où ce sont des fonctions qui ne renvoient que des booléens de longueur 1. Vous souhaitez utiliser les formes courtes si les vecteurs sont de longueur éventuellement> 1. Donc, si vous n'êtes pas absolument sûr, vous devez d'abord vérifier, ou utiliser le formulaire court, puis utiliser allet anypour le réduire à une longueur pour une utilisation dans les instructions de flux de contrôle, comme if.

Les fonctions allet anysont souvent utilisées sur le résultat d'une comparaison vectorisée pour voir si toutes ou certaines des comparaisons sont vraies, respectivement. Les résultats de ces fonctions sont sûrs de longueur 1, ils peuvent donc être utilisés dans les clauses if, tandis que les résultats de la comparaison vectorisée ne le sont pas. (Bien que ces résultats puissent être utilisés dans ifelse.

Une dernière différence: le &&et ||n'évalue que le nombre de termes nécessaires (ce qui semble être ce que l'on entend par court-circuit). Par exemple, voici une comparaison utilisant une valeur non définie a; s'il ne court-circuitait pas, comme &et |pas, cela donnerait une erreur.

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

Enfin, voir la section 8.2.17 dans The R Inferno , intitulée "and and and and".

Aaron a laissé Stack Overflow
la source
Je compare des logiques de longueur 1. La documentation n'est pas claire sur la raison pour laquelle elle est préférée pour le contrôle de flux. Est-ce parce qu'il utilise le "court-circuit" des réponses de @ Theo et a donc de meilleures performances?
SFun28
Nan. Utilisez simplement le formulaire court '&' - les réponses de court-circuit sont incorrectes.
M. Tibbits
1
Non, car cela garantit de n'avoir qu'une seule réponse VRAI / FAUX. Les formes plus courtes pourraient en résulter c(TRUE, FALSE)et la ifdéclaration ne serait pas claire. Si vous êtes certain que tout a une longueur de 1, alors oui, l'un ou l'autre ferait l'affaire, et vous avez raison de dire que le "court-circuit" est la raison pour laquelle vous en préférez un. Un mot d'avertissement cependant, assurez-vous que vous êtes sûr à 100% qu'ils ne peuvent être que de la longueur un. Vous pouvez obtenir des bugs vraiment loufoques autrement.
Aaron a quitté Stack Overflow le
9
@ SFun28: Oui, le court-circuit est la raison pour laquelle il a préféré le contrôle de flux. En plus de meilleures performances, vous ne souhaiterez peut-être pas évaluer tous les arguments. L'exemple canonique est donné ?is.Rpour vérifier si vous utilisez R ou S-Plus. if(exists("is.R") && is.function(is.R) && is.R()). Si is.Rn'existe pas, alors vous ne voulez pas évaluer is.function(is.R)car cela générera une erreur. De même, si ce is.Rn'est pas une fonction, vous ne voulez pas l'appeler comme si elle l'était.
Richie Cotton
2
Dans la version actuelle de R inferno, la section pertinente est désormais 8.2.17 "and and andand"
Silverfish
34

La réponse au sujet du "court-circuit" est potentiellement trompeuse, mais a une certaine vérité (voir ci-dessous). Dans le langage R / S, &&et ||n'évaluez que le premier élément du premier argument. Tous les autres éléments d'un vecteur ou d'une liste sont ignorés, quelle que soit la première valeur. Ces opérateurs sont conçus pour fonctionner avec la if (cond) {} else{}construction et au contrôle des programmes directs plutôt que de construire de nouveaux vecteurs .. Les &et les |opérateurs sont conçus pour fonctionner sur des vecteurs, donc ils seront appliqués « en parallèle », pour ainsi dire, sur toute la longueur l'argument le plus long. Les deux vecteurs doivent être évalués avant d'effectuer les comparaisons. Si les vecteurs n'ont pas la même longueur, le recyclage de l'argument le plus court est alors effectué.

Lorsque les arguments vers &&ou ||sont évalués, il y a un "court-circuit" en ce sens que si l'une des valeurs successives de gauche à droite est déterminante, les évaluations cessent et la valeur finale est renvoyée.

> 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

L'avantage du court-circuit n'apparaîtra que lorsque les arguments mettent longtemps à être évalués. Cela se produit généralement lorsque les arguments sont des fonctions qui traitent des objets plus gros ou ont des opérations mathématiques plus complexes.

IRTFM
la source
"court-circuiter" est un nouveau terme pour moi, mais il me semble que la réponse le décrivant est en accord avec ce que vous dites &&et ||.
Aaron a quitté Stack Overflow le
@DWin - dans le cas d'opérations sur des logiques de longueur 1, elles sont équivalentes, n'est-ce pas? J'essaie de comprendre pourquoi ils sont préférés dans le flux de contrôle, comme l'indique la documentation. De plus, R a-t-il une construction de "court-circuit"?
SFun28
Ils NE SONT PAS équivalents pour des vecteurs de longueur> 1
M. Tibbits
2
Il est vrai que si les arguments de &&sont des fonctions et que le premier est faux, le second ne sera pas évalué. Ce n'est pas vrai pour l'un &ou l' autre ifelsequi évaluera les deux arguments.
IRTFM
N'est-ce pas ce que dit la réponse de Théo sur le court-circuit?
Aaron a quitté Stack Overflow le
25

&&et ||sont ce qu'on appelle des "courts-circuits". Cela signifie qu'ils n'évalueront pas le deuxième opérande si le premier opérande est suffisant pour déterminer la valeur de l'expression.

Par exemple, si le premier opérande &&est faux, il n'y a aucun intérêt à évaluer le second opérande, car il ne peut pas changer la valeur de l'expression ( false && trueet false && falsesont tous deux faux). Il en va de même ||lorsque le premier opérande est vrai.

Vous pouvez en savoir plus à ce sujet ici: http://en.wikipedia.org/wiki/Short-circuit_evaluation Dans le tableau de cette page, vous pouvez voir que cela &&équivaut à AndAlsoVB.NET, auquel je suppose que vous faites référence.

Théo
la source
3
Cela devrait être une preuve suffisante qu'il est court circuit: f <- function() { print('hello'); TRUE }; FALSE && f(). Modifiez &et notez que la fonction est évaluée. QED.
Theo
2
Théo, oui, tu as raison &&et ||court-circuit. Mais c'est vraiment un point assez mineur dans les comparaisons entre la forme courte et la forme longue; il est beaucoup plus important de comprendre ce que chacun fait lorsque les entrées sont des vecteurs.
Aaron a quitté Stack Overflow le
2
@MTibbits En fait, ce n'est pas une réponse complète, mais l'énoncé sur les courts-circuits est correct . Essayez F & {message("Boo!");T}et F && {message("Boo!");T}.
mbq