Operatory logiczne && i ||


252

Zgodnie z definicją języka R różnica między &i &&(odpowiednio |i ||) polega na tym, że pierwsze jest wektoryzowane, a drugie nie.

Zgodnie z tekstem pomocy czytam różnicę podobną do różnicy między „And” i „AndAlso” (odpowiednio „Or” i „OrElse”) ... Znaczenie: To nie wszystkie oceny, jeśli nie muszą być (tzn. A, B lub C są zawsze prawdziwe, jeśli A jest prawdziwe, więc przestań oceniać, czy A jest prawdziwe)

Czy ktoś mógłby tu rzucić światło? Czy jest też AndAlso i OrElse w R?


Zobacz także podobne pytania na stackoverflow.com/q/6933598/210673 i stackoverflow.com/q/7953833/210673 (teraz zamknięte jako duplikat).
Aaron opuścił Stack Overflow

3
Myślę, że && i || są źle zaimplementowane w R. W innych językach są one operatorami warunkowymi AND i OR, wykonują logiczne operacje logiczne AND lub OR, ale oceniają tylko drugi argument, jeśli to konieczne. W R nie rób nic przydatnego.
skan

Odpowiedzi:


340

Krótsze są wektoryzowane, co oznacza, że ​​mogą zwrócić wektor w następujący sposób:

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

Dłuższa forma ocenia od lewej do prawej, badając tylko pierwszy element każdego wektora, więc powyższe daje

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

Jak mówi strona pomocy, powoduje to, że dłuższa forma jest „odpowiednia do programowania kontroli przepływu i zwykle jest preferowana w klauzulach if”.

Więc chcesz używać długich formularzy tylko wtedy, gdy masz pewność, że wektory mają długość jeden.

Powinieneś być absolutnie pewien, że twoje wektory mają tylko długość 1, na przykład w przypadkach, gdy są funkcjami, które zwracają tylko logiczne długości 1. Chcesz użyć krótkich formularzy, jeśli wektory mają długość prawdopodobnie> 1. Więc jeśli nie masz absolutnej pewności, powinieneś albo najpierw sprawdzić, albo użyć krótkiego formularza, a następnie użyć alli anyzmniejszyć go do długości jednego do użycia w instrukcjach przepływu kontroli, takich jak if.

Funkcje alli anysą często używane w wyniku porównania wektorowego, aby sprawdzić, czy odpowiednio wszystkie lub jakiekolwiek porównania są prawdziwe. Wyniki tych funkcji z pewnością będą miały długość 1, więc są odpowiednie do użycia w klauzulach if, podczas gdy wyniki z wektoryzowanego porównania nie są. (Chociaż wyniki te byłyby odpowiednie do użycia w ifelse.

Jedna końcowa różnica: &&i ||tylko oceniają tyle terminów, ile potrzebują (co wydaje się być tym, co rozumie się przez zwarcie). Na przykład, oto porównanie przy użyciu niezdefiniowanej wartości a; jeśli nie spowoduje zwarcia, tak jak &i |nie, spowoduje błąd.

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

Na koniec zobacz sekcję 8.2.17 w R Inferno , zatytułowaną „oraz and and and”.


Porównuję logikę długości 1. Dokumentacja nie wyjaśnia, dlaczego preferuje przepływ kontrolny. Czy to dlatego, że wykorzystuje „zwarcie” z odpowiedzi @ Theo, a zatem ma lepszą wydajność?
SFun28

nie. Wystarczy użyć krótkiego formularza „&” - odpowiedzi na zwarcie są nieprawidłowe.
M. Tibbits,

1
Nie, ponieważ gwarantuje tylko jedną odpowiedź PRAWDA / FAŁSZ. Krótsze formy mogą skutkować c(TRUE, FALSE), a ifstwierdzenie nie byłoby jasne. Jeśli jesteś pewien, że wszystko ma długość 1, to tak, zrobi to i masz rację, że „zwarcie” jest powodem, dla którego preferujesz jeden. Słowo ostrzeżenia, upewnij się, że masz 100% pewności, że mogą być tylko pierwsze. W przeciwnym razie możesz dostać naprawdę głupie błędy.
Aaron opuścił Stack Overflow

9
@ SFun28: Tak, zwarcie jest powodem, dla którego preferuje się kontrolę przepływu. Oprócz lepszej wydajności możesz nie chcieć oceniać wszystkich argumentów. Podano kanoniczny przykład ?is.Rsprawdzania, czy korzystasz z R czy S-Plus. if(exists("is.R") && is.function(is.R) && is.R()). Jeśli is.Rnie istnieje, nie chcesz oceniać, is.function(is.R)ponieważ spowoduje to błąd. Podobnie, jeśli is.Rnie jest funkcją, nie chcesz jej tak nazywać.
Richie Cotton

2
W obecnej wersji piekła R odpowiednia sekcja to teraz 8.2.17 „oraz andand”
Silverfish

34

Odpowiedź na temat „zwarcia” jest potencjalnie myląca, ale zawiera pewną prawdę (patrz poniżej). W języku R / S &&i ||oceniaj tylko pierwszy element w pierwszym argumencie. Wszystkie inne elementy w wektorze lub liście są ignorowane bez względu na pierwszą wartość. Operatory te są zaprojektowane do pracy z if (cond) {} else{}konstrukcją i do bezpośredniego sterowania programem, a nie do konstruowania nowych wektorów. Operatory &i |są zaprojektowane do pracy z wektorami, więc będą one stosowane „równolegle”, że tak powiem, wzdłuż najdłuższy argument. Oba wektory należy ocenić przed dokonaniem porównań. Jeśli wektory nie są tej samej długości, następuje ponowne przetworzenie krótszego argumentu.

Gdy argumenty do &&lub ||są oceniane, następuje „zwarcie” polegające na tym, że jeśli dowolna z następujących po sobie wartości od lewej do prawej ma znaczenie determinujące, wówczas oceny są przerywane i zwracana jest wartość końcowa.

> 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

Zaleta zwarcia pojawi się tylko wtedy, gdy ocena argumentów zajmuje dużo czasu. Zwykle ma to miejsce, gdy argumentami są funkcje, które albo przetwarzają większe obiekty, albo mają bardziej złożone operacje matematyczne.


„zwarcie” jest dla mnie nowym terminem, ale wydaje mi się, że odpowiedź opisująca to zgadza się z tym, co mówisz o &&i ||.
Aaron opuścił Stack Overflow

@DWin - w przypadku operacji logicznych o długości powyżej 1 są one równoważne, prawda? Próbuję zrozumieć, dlaczego są one preferowane w przepływie kontroli, jak stwierdza dokumentacja. Ponadto, czy R ma konstrukcję zwarcia?
SFun28

NIE są one równoważne dla wektorów o długości> 1
M. Tibbits

2
Prawdą jest, że jeśli argumentami &&są funkcje, a pierwszy jest fałszywy, to drugi nie zostanie oceniony. Nie dotyczy to &ani jednego, ani tego, ifelsektóry oceni oba argumenty.
IRTFM,

Czy nie tak mówi również Theo o zwarciu?
Aaron opuścił Stack Overflow

25

&&i ||są nazywane „zwarciem”. Oznacza to, że nie będą oceniać drugiego argumentu, jeśli pierwszy argument będzie wystarczający do ustalenia wartości wyrażenia.

Na przykład, jeśli pierwszy argument &&jest fałszywy, nie ma sensu oceniać drugiego argumentu, ponieważ nie może on zmienić wartości wyrażenia ( false && truei false && falseoba są fałszywe). To samo dotyczy, ||gdy pierwszy operand jest prawdziwy.

Możesz przeczytać więcej na ten temat tutaj: http://en.wikipedia.org/wiki/Short-circuit_evaluation Z tabeli na tej stronie możesz zobaczyć, że &&jest to odpowiednik AndAlsoVB.NET, do którego zakładam, że masz na myśli.


3
To powinno być wystarczającym dowodem, że jest krótki spięciom: f <- function() { print('hello'); TRUE }; FALSE && f(). Zmień &i zauważ, że funkcja jest oceniana. CO BYŁO DO OKAZANIA.
Theo

2
Theo, tak, masz rację &&i ||zwarcie. Ale to naprawdę niewielka kwestia w porównaniu krótkiej i długiej formy; o wiele ważniejsze jest zrozumienie, co każdy robi, gdy dane wejściowe są wektorami.
Aaron opuścił Stack Overflow

2
@MTibbits W rzeczywistości nie jest to kompletna odpowiedź, ale stwierdzenie dotyczące zwarcia jest poprawne . Spróbuj F & {message("Boo!");T}i F && {message("Boo!");T}.
mbq
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.