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


252

Відповідно до визначення мови R , різниця між &і &&(відповідно |і ||) полягає в тому, що перше векторизується, а друге - ні.

Відповідно до тексту довідки , я читаю різницю, подібну різниці між "І" та "AndAlso" (відповідно "Або" та "OrElse") ... Значення: Це не всі оцінки, якщо вони не повинні бути (тобто A або B або C завжди відповідає дійсності, якщо A є правдою, тому припиніть оцінювати, чи A є правдою)

Може хтось тут пролити світло? Крім того, чи є AndAlso та OrElse в R?


Також див. Подібні запитання на веб-сайті stackoverflow.com/q/6933598/210673 та stackoverflow.com/q/7953833/210673 (тепер закритий як дублікат).
Аарон вийшов із переповнення стека

3
Я думаю && і || погано реалізовані в Р. В інших мовах вони умовні оператори AND і OR, вони виконують логічні операції AND або OR булі, але лише оцінюють його другий операнд, якщо це необхідно. У R не робіть нічого корисного.
скан

Відповіді:


340

Більш короткі - векторизовані, тобто вони можуть повернути вектор, наприклад:

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

Чим довша форма оцінюється зліва направо, вивчаючи лише перший елемент кожного вектора, тому наведене вище дає

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

Як зазначається на сторінці довідки, це робить більш довгу форму, "підходящу для програмування потоку управління, і [є], як правило, бажано в пунктах, якщо передбачено".

Таким чином, ви хочете використовувати довгі форми лише тоді, коли ви впевнені, що вектори - це одна довжина.

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

Функції allі anyчасто використовуються за результатами векторизованого порівняння, щоб побачити, чи справді все чи будь-яке порівняння. Результати цих функцій, безумовно, будуть довжиною 1, тому вони є придатними для використання, якщо пункти, тоді як результати векторизованого порівняння не є. (Хоча ці результати були б доречними для використання в 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 у " The R Inferno " під назвою "і та і".


Я порівнюю логіки довжини 1. У документації не ясно, чому її віддають перевагу контрольному потоку. Це тому, що він використовує "коротке замикання" з відповідей @ Тео і, таким чином, має кращі показники?
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 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

Перевага короткого замикання з’явиться лише тоді, коли аргументи потребують тривалого часу для оцінки. Зазвичай це відбувається, коли аргументи - це функції, які або обробляють більші об'єкти, або мають складніші математичні операції.


"коротке замикання" - це новий термін для мене, але мені здається, що відповідь, що описує його, відповідає тому, про що ви говорите &&і ||.
Аарон залишив стек переповнення

@DWin - у випадку експлуатації логіки довжиною 1 вони еквівалентні правильно? Я намагаюся зрозуміти, чому вони віддають перевагу в контрольному потоці, як зазначено в документації. Також, чи має R конструкцію "короткого замикання"?
SFun28

Вони НЕ еквівалентні для векторів довжини> 1
М. Тіббіт

2
Це правда, що якщо аргументи &&є функціями, а перший - помилковим, то другий не буде оцінюватися. Це не вірно для будь-якого &або ifelseякий буде оцінювати обидва аргументи.
IRTFM

Чи не про це говорить і відповідь Тео про коротке замикання?
Аарон залишив стек переповнення

25

&&і ||є те, що називається "коротке замикання". Це означає, що вони не будуть оцінювати другий операнд, якщо першого операнда буде достатньо для визначення значення виразу.

Наприклад, якщо перший операнд to &&false, то немає значення в оцінюванні другого операнда, оскільки він не може змінити значення виразу ( 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}.
mbq
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.