โอเปอเรเตอร์บูลีน && และ ||


252

ตามคำนิยามภาษา R ความแตกต่างระหว่าง&และ&&(ตามลําดับ|และ||) คือการที่อดีตถูก vectorized ในขณะที่หลังไม่ได้

ตามข้อความช่วยเหลือฉันอ่านความแตกต่างคล้ายกับความแตกต่างระหว่าง "และ" และ "AndAlso" (ตามลำดับ "หรือ" และ "OrElse") ... ความหมาย: นั่นไม่ใช่การประเมินทั้งหมดหากพวกเขาไม่จำเป็นต้องเป็น (เช่น A หรือ B หรือ C เป็นจริงเสมอถ้า A เป็นจริงดังนั้นหยุดประเมินถ้า A เป็นจริง)

มีคนช่วยแสงที่นี่ได้ไหม นอกจากนี้ยังมี AndAlso และ OrElse ใน R หรือไม่


ดูคำถามที่คล้ายกันได้ที่stackoverflow.com/q/6933598/210673และstackoverflow.com/q/7953833/210673 (ตอนนี้ปิดเหมือนกัน)
Aaron ออกจาก Stack Overflow

3
ฉันคิดว่า && และ || ถูกนำมาใช้อย่างไม่ดีใน R ในภาษาอื่น ๆ พวกเขาเป็นเงื่อนไข AND และ OR หรือตัวดำเนินการพวกเขาดำเนินการตรรกะ AND หรือ OR หรือการบูลีน แต่จะประเมินตัวถูกดำเนินการที่สองหากจำเป็น ใน R ไม่ทำอะไรที่มีประโยชน์
skan

คำตอบ:


340

อันที่สั้นกว่านั้นคือ vectorized ซึ่งหมายความว่าพวกมันสามารถคืนค่าเวกเตอร์ได้ดังนี้:

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

แบบฟอร์มที่ยาวกว่าจะประเมินจากซ้ายไปขวาเป็นการตรวจสอบเฉพาะองค์ประกอบแรกของแต่ละเวกเตอร์เท่านั้นดังนั้นสิ่งที่กล่าวมาข้างต้นจะให้

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

ตามที่หน้าความช่วยเหลือบอกว่าสิ่งนี้จะทำให้ฟอร์มยาวขึ้น "เหมาะสำหรับการเขียนโปรแกรมควบคุมโฟลว์และโดยทั่วไปแล้ว [ต้องการ] ในกรณีที่คำสั่ง"

คุณต้องการใช้รูปแบบยาวเฉพาะเมื่อคุณแน่ใจว่าเวกเตอร์นั้นยาวเท่ากัน

คุณควรจะอย่างบางเวกเตอร์ของคุณเป็นเพียงระยะเวลา 1 เช่นในกรณีที่พวกเขาจะมีฟังก์ชั่นว่าการกลับมามีความยาวเพียง 1 booleans คุณต้องการใช้แบบฟอร์มสั้น ๆ หากเวกเตอร์มีความยาวได้> 1 ดังนั้นหากคุณไม่แน่ใจจริงๆคุณก็ควรจะตรวจสอบก่อนหรือใช้แบบฟอร์มสั้น ๆ แล้วใช้allและเพื่อลดความมันให้มีความยาวหนึ่งสำหรับการใช้งานในงบการควบคุมการไหลเช่นanyif

ฟังก์ชัน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หัวข้อ "and and andand"


ฉันกำลังเปรียบเทียบลอจิกที่มีความยาว 1. เอกสารไม่ชัดเจนเกี่ยวกับสาเหตุที่เป็นที่ต้องการสำหรับโฟลว์การควบคุม นั่นเป็นเพราะใช้คำว่า "ลัดวงจร" จากคำตอบของ @ Theo และมีประสิทธิภาพที่ดีขึ้นหรือไม่
SFun28

Nope เพียงใช้รูปแบบย่อ '&' คำตอบลัดวงจรไม่ถูกต้อง
M. Tibbits

1
ไม่เพราะมันรับประกันว่าจะมีคำตอบ TRUE / FALSE เพียงคำเดียว แบบฟอร์มที่สั้นกว่าอาจส่งผลc(TRUE, FALSE)ให้และifคำสั่งจะไม่ชัดเจน หากคุณแน่ใจว่าทุกอย่างมีความยาว 1 ใช่แล้วคุณก็ทำได้และคุณถูกต้องแล้วว่า "ไฟฟ้าลัดวงจร" เป็นเหตุผลที่เลือกอย่างใดอย่างหนึ่ง คำเตือนแม้ว่าให้แน่ใจว่าคุณ 100% แน่ใจว่าพวกเขาจะมีความยาวเพียงหนึ่ง คุณสามารถรับข้อบกพร่องที่โง่จริง ๆ
แอรอนออกจาก Stack Overflow

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ไม่ใช่ฟังก์ชั่นคุณไม่ต้องการเรียกมันราวกับว่ามันเป็น
Richie Cotton

2
ในเวอร์ชั่นปัจจุบันของ R inferno ส่วนที่เกี่ยวข้องอยู่ในขณะนี้ 8.2.17 "และ andandand"
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

ข้อดีของการลัดวงจรจะปรากฏเฉพาะเมื่อข้อโต้แย้งใช้เวลานานในการประเมิน โดยทั่วไปจะเกิดขึ้นเมื่ออาร์กิวเมนต์เป็นฟังก์ชันที่ประมวลผลวัตถุที่ใหญ่กว่าหรือมีการดำเนินการทางคณิตศาสตร์ที่ซับซ้อนกว่า


"ลัดวงจร" เป็นคำใหม่ให้ฉัน แต่มันดูเหมือนว่าผมว่าคำตอบที่อธิบายว่าเห็นด้วยกับสิ่งที่คุณพูดเกี่ยวกับและ&& ||
แอรอนออกจาก Stack Overflow

@DWin - ในกรณีที่มีการดำเนินการเกินความยาว 1 ตรรกะพวกเขาจะเท่าเทียมกันใช่มั้ย ฉันพยายามที่จะเข้าใจว่าทำไมจึงเป็นที่ต้องการในโฟลว์การควบคุมตามสถานะเอกสาร นอกจากนี้ R มีโครงสร้างแบบ "ลัดวงจร" หรือไม่
SFun28

พวกเขาจะไม่เทียบเท่าเวกเตอร์ของความยาว> 1
เอ็ม Tibbits

2
มันเป็นความจริงที่ว่าถ้าข้อโต้แย้งที่จะ&&เป็นฟังก์ชั่นและคนแรกเป็นเท็จแล้วที่สองจะไม่ได้รับการประเมิน นั่นไม่เป็นความจริงสำหรับอย่างใดอย่างหนึ่ง&หรือifelseที่จะประเมินข้อโต้แย้งทั้งสอง
IRTFM

นั่นไม่ใช่สิ่งที่คำตอบของธีโอเกี่ยวกับการลัดวงจรก็บอกเช่นกัน?
แอรอนออกจาก Stack Overflow

25

&&และ||เป็นสิ่งที่เรียกว่า "การลัดวงจร" นั่นหมายความว่าพวกมันจะไม่ประเมินค่าตัวถูกดำเนินการตัวที่สองถ้าตัวถูกดำเนินการตัวแรกนั้นเพียงพอที่จะกำหนดค่าของนิพจน์ได้

ตัวอย่างเช่นถ้าตัวถูกดำเนินการแรก&&เป็น false จะไม่มีประโยชน์ในการประเมินตัวถูกดำเนินการตัวที่สองเนื่องจากไม่สามารถเปลี่ยนค่าของนิพจน์ได้ ( false && trueและfalse && falseทั้งคู่เป็นเท็จ) เช่นเดียวกับ||เมื่อตัวถูกดำเนินการตัวแรกเป็นจริง

คุณสามารถอ่านเพิ่มเติมเกี่ยวกับเรื่องนี้ได้ที่นี่: http://en.wikipedia.org/wiki/Short-circuit_evaluationจากตารางในหน้านั้นคุณจะเห็นว่า&&เทียบเท่ากับAndAlsoใน VB.NET ซึ่งฉันถือว่าคุณกำลังอ้างถึง


3
นี่ควรจะพิสูจน์ได้ว่ามันเป็นการลัดวงจร: f <- function() { print('hello'); TRUE }; FALSE && f(). เปลี่ยนเป็น&และสังเกตว่ามีการประเมินฟังก์ชัน QED
Theo

2
โดยใช่คุณถูกต้อง&&และ||ลัดวงจร แต่นั่นเป็นจุดที่ค่อนข้างเล็กเมื่อเปรียบเทียบระหว่างแบบสั้นกับแบบยาว มันสำคัญมากที่จะต้องเข้าใจว่าแต่ละอันทำอะไรเมื่ออินพุทเป็นเวกเตอร์
แอรอนออกจาก Stack Overflow

2
@MTibbits ในความเป็นจริงนี้ไม่ได้เป็นคำตอบที่สมบูรณ์ แต่คำสั่งเกี่ยวกับไฟฟ้าลัดวงจรถูกต้อง ลองและF & {message("Boo!");T} F && {message("Boo!");T}
mbq
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.