Булевы операторы && и ||

252

Согласно определению языка R , различие между &и &&(соответственно |и ||) состоит в том, что первое векторизовано, а второе нет.

Согласно тексту справки , я прочел разницу, похожую на разницу между «И» и «AndAlso» (соответственно «И» и «OrElse») ... Значение: это не все оценки, если они не должны быть (то есть A или B или C всегда верны, если A истинно, поэтому прекратите оценку, если A истинно)

Может ли кто-то пролить свет здесь? Кроме того, есть AndAlso и OrElse в R?

SFun28
источник
Также смотрите похожие вопросы по адресу stackoverflow.com/q/6933598/210673 и stackoverflow.com/q/7953833/210673 (теперь закрыт как дубликат).
Аарон оставил переполнение стека
3
Я думаю && и || плохо реализованы в R. На других языках они являются условными операторами И и ИЛИ, они выполняют логические логические операции И или ИЛИ, но оценивают свой второй операнд только при необходимости. В R не делай ничего полезного.
Скан

Ответы:

340

Более короткие из них векторизованы, что означает, что они могут возвращать вектор, например так:

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

Более длинная форма оценивает слева направо, рассматривая только первый элемент каждого вектора, поэтому приведенное выше дает

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

Как говорится на странице справки, это делает более длинную форму «подходящей для программирования потока управления и обычно предпочтительной в выражениях if».

Таким образом, вы хотите использовать длинные формы только тогда, когда вы уверены, что векторы имеют длину один.

Вы должны быть абсолютно уверены, что ваши векторы имеют только длину 1, например, в случаях, когда они являются функциями, которые возвращают только логические значения длины 1. Вы хотите использовать короткие формы, если векторы имеют длину, возможно,> 1. Так что, если вы не совсем уверены, вы должны сначала проверить или использовать краткую форму, а затем использовать allи anyсократить ее до длины для использования в операторах потока управления, например if.

Функции allи anyчасто используются в результате векторизованного сравнения, чтобы увидеть, являются ли все или какие-либо из сравнений истинными, соответственно. Результаты этих функций обязательно имеют длину 1, поэтому они подходят для использования в предложениях if, а результаты векторизованного сравнения - нет. (Хотя эти результаты будут подходящими для использования в ifelse.

Одно заключительное отличие: « &&и» ||оценивают столько терминов, сколько им нужно (что, по-видимому, означает короткое замыкание). Например, вот сравнение с использованием неопределенного значения a; если бы оно не закорачивалось, как &и |нет, это дало бы ошибку.

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

Наконец, см. Раздел 8.2.17 в R Inferno , озаглавленный «and and andand».

Аарон оставил переполнение стека
источник
Я сравниваю логику длины 1. В документации не ясно, почему она предпочтительна для потока управления. Это потому, что он использует «короткое замыкание» из ответов @ Theo и, следовательно, имеет лучшую производительность?
SFun28
Нет. Просто используйте краткую форму '&' - ответы о коротком замыкании неверны.
М. Тиббитс
1
Нет, потому что это гарантирует только один ответ ИСТИНА / ЛОЖЬ. Более короткие формы могут привести к c(TRUE, FALSE), и ifутверждение не будет ясным. Если вы уверены, что все имеет длину 1, тогда да, любой из них подойдет, и вы правы в том, что причиной является «короткое замыкание». Предупреждение, хотя, убедитесь, что вы на 100% уверены, что они могут быть только одного размера. В противном случае вы можете получить действительно глупые ошибки.
Аарон оставил переполнение стека
9
@ SFun28: Да, короткое замыкание - это причина, по которой он предпочитает управление потоком. Помимо повышения производительности, вы можете не захотеть оценивать все аргументы. Канонический пример приведен ?is.Rдля проверки, используете ли вы R или S-Plus. if(exists("is.R") && is.function(is.R) && is.R()), Если is.Rне существует, то вы не хотите оценивать, is.function(is.R)поскольку он выдаст ошибку. Аналогично, если is.Rэто не функция, вы не хотите вызывать ее так, как если бы она была.
Ричи Коттон
2
В текущей версии R inferno соответствующий раздел теперь находится в 8.2.17 "and and andand"
Silverfish
34

Ответ о «коротком замыкании» может ввести в заблуждение, но в нем есть доля правды (см. Ниже). На языке R / S &&и ||оценивать только первый элемент в первом аргументе. Все остальные элементы в векторе или списке игнорируются независимо от значения первых. Эти операторы предназначены для работы с if (cond) {} else{}строительства и прямого программного управления , а не строить новые векторы .. &и |операторы предназначены для работы на векторах, поэтому они будут применяться «параллельно», так сказать, по длине самый длинный аргумент. Оба вектора должны быть оценены перед сравнением. Если векторы не имеют одинаковую длину, выполняется повторное использование более короткого аргумента.

Когда аргументы для &&или ||оцениваются, возникает «короткое замыкание» в том, что если какое-либо из последовательных значений слева направо является определяющим, то оценки прекращаются и возвращается окончательное значение.

> 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

Преимущество короткого замыкания проявляется только тогда, когда для оценки аргументов требуется много времени. Это обычно происходит, когда аргументы являются функциями, которые либо обрабатывают большие объекты, либо выполняют более сложные математические операции.

IRTFM
источник
«короткое замыкание» это новый термин для меня, но мне кажется , что ответ , описывающее это согласуется с тем, что вы говорите о &&и ||.
Аарон оставил переполнение стека
@DWin - в случае работы с логиками длины 1 они эквивалентны, верно? Я пытаюсь понять, почему они предпочтительны в потоке управления, как говорится в документации. Кроме того, R имеет конструкцию "короткого замыкания"?
SFun28
Они НЕ эквивалентны для векторов длины> 1
М. Тиббитс
2
Это правда, что если аргументы для &&являются функциями, а первый является ложным, то второй не будет оцениваться. Это не верно ни для одного, &или ifelseдля оценки обоих аргументов.
IRTFM
Разве это не то, что ответ Тео о коротком замыкании говорит тоже?
Аарон оставил переполнение стека
25

&&и то ||, что называется "короткое замыкание" Это означает, что они не будут оценивать второй операнд, если первого операнда достаточно для определения значения выражения.

Например, если первый операнд &&является ложным, тогда нет смысла оценивать второй операнд, поскольку он не может изменить значение выражения ( false && trueи false && falseоба являются ложными). То же самое касается ||первого операнда.

Вы можете прочитать больше об этом здесь: http://en.wikipedia.org/wiki/Short-circuit_evaluation Из таблицы на этой странице вы можете увидеть, что &&эквивалентно AndAlsoVB.NET, на который, я полагаю, вы ссылаетесь.

Тео
источник
3
Это должно быть достаточным доказательством того , что это короткое замыкание: f <- function() { print('hello'); TRUE }; FALSE && f(). Перейдите &и обратите внимание, что функция оценивается. QED.
Тео
2
Тео, да, ты прав, что &&и ||короткое замыкание. Но это действительно довольно незначительный момент в сравнении между короткой формой и длинной формой; гораздо важнее понять, что каждый из них делает, когда входные данные являются векторами.
Аарон оставил переполнение стека
2
@MTibbits На самом деле это не полный ответ, но утверждение о коротком замыкании является правильным . Попробуйте F & {message("Boo!");T}и F && {message("Boo!");T}.
МБК