Menu

If Else ב-R: if, else if, ifelse() ו-switch()

לוגיקה מותנית ב-R: התחביר של if/else if/else, מלכודת הסוגריים המסולסלים ששוברת סקריפטים, ifelse() הווקטורי לווקטורים שלמים, ו-switch() לבחירה בין כמה אפשרויות.

בדף הזה יש עורכים שאפשר להריץ - לערוך, להריץ ולראות את הפלט מיד.

משפט ה-if

משפט if ב-R מריץ בלוק קוד רק כשתנאי הוא TRUE. התנאי נכתב בסוגריים עגולים, הקוד בסוגריים מסולסלים, ו-else אופציונלי קובע מה קורה אחרת:

התנאי score >= 60 מוערך ל-TRUE יחיד, ולכן הענף הראשון רץ. אופרטורי ההשוואה והאופרטורים הלוגיים, ==, >=, &&, %in% וחבריהם, הם אבני הבניין של התנאים האלה.

ליותר משתי תוצאות, שרשרו בדיקות עם else if. R עובר על השרשרת מהתנאי הראשון ומטה ומריץ את הענף הראשון שהתנאי שלו TRUE, ומדלג על השאר:

הסדר חשוב: מכיוון ש-85 >= 80 נבדק לפני 85 >= 70, הציון הוא "B". אם הייתם ממיינים את הבדיקות בכיוון ההפוך, כל ציון מעל 70 היה מקבל "C".

מלכודת הסוגריים: איפה else חייב להיות

זו השגיאה שנושכת כמעט את הסקריפט הראשון של כל אחד ב-R. בסקריפט (או בכל דבר שמורץ עם Rscript), else חייב להופיע באותה שורה של הסוגר המסולסל הסוגר של הענף שלפניו. זה נכשל:

if (score >= 60) {
  print("You passed")
}
else {              # Error: unexpected 'else'
  print("Try again")
}

למה: R מנתח משפט אחר משפט. כשהוא מגיע ל-} בתחילת שורה, משפט ה-if שלם מבחינה תחבירית, ו-R מעריך אותו מיד. ה-else בשורה הבאה מגיע כתחילתו של משפט חדש, ומשפט לא יכול להתחיל ב-else. התיקון הוא הדפוס שמשמש לאורך כל העמוד הזה:

if (score >= 60) {
  print("You passed")
} else {            # brace and else on the same line
  print("Try again")
}

בתוך גוף של פונקציה או בתוך כל זוג סוגריים מסולסלים חיצוני הכלל הנוקשה מתרכך (R ממשיך לקרוא עד שהסוגר החיצוני נסגר), אבל אל תסתמכו על זה. הסגנון } else { עובד בכל מקום והוא מה שמדריכי הסגנון של R קובעים.

התנאי חייב להיות TRUE או FALSE יחיד

if() דורש ערך לוגי אחד בדיוק. שני דברים מפרים את זה, ושניהם שגיאות:

if (NA) print("hi")
# Error: missing value where TRUE/FALSE needed

if (c(TRUE, FALSE)) print("hi")
# Error: the condition has length > 1

המקרה של NA חשוב בפועל, כי השוואות עם נתונים חסרים מייצרות NA: אם x הוא NA, אז x > 10 הוא NA, ו-if שמקבל את התנאי הזה עוצר את הסקריפט. הדפוס ההגנתי משתמש ב-&& עם קצר חשמלי (short-circuit):

מכיוון ש-!is.na(x) הוא FALSE, החלק x > 10 לעולם לא מוערך ושום NA לא מגיע לתנאי. האופן שבו NA מתפשט דרך השוואות מוסבר בערכים חסרים.

שגיאת האורך הגדול מ-1 (נאכפת מאז R 4.2; לפני כן R השתמש בשקט באיבר הראשון) בדרך כלל אומרת שהתכוונתם לאחד מאלה: any(v > 5) אם התאמה אחת מספיקה, all(v > 5) אם כל איבר חייב לעבור, או ifelse() אם רציתם תשובה לכל איבר, וזה הנושא של הסעיף הבא.

ifelse(): If Else וקטורי

if מחליט פעם אחת. ifelse(test, yes, no) מחליט עבור כל איבר בווקטור ומחזיר וקטור באותו אורך:

כל איבר ב-temps נבדק בנפרד: "hot" "mild" "mild" "hot" "mild". זה הכלי לגזירת וקטור חדש או עמודה חדשה ב-data frame מתוך קיימים, בלי צורך בלולאה.

בשונה מ-if, ifelse() מטפל בערכים חסרים בחן: NA בבדיקה מניב NA בתוצאה ולא שגיאה:

אפשר לקנן קריאות ifelse() לפיצול לשלושה, ובעומק הזה זה עדיין קריא:

אבל עצרו שם. שלוש קריאות ifelse() מקוננות או יותר הופכות לחידה של התאמת סוגריים; בשלב הזה פנו ל-cut() (לטווחים מספריים) או ל-dplyr::case_when(), שמציב כל תנאי בשורה משלו.

switch() לבחירה בין כמה אפשרויות

כשמשווים ערך אחד לרשימה של שמות ידועים, ולא בודקים טווחים, שרשרת ארוכה של else if היא הכלי המסורבל. switch() אומר את זה ישירות:

שלוש התנהגויות שכדאי להכיר:

  • התאמה: switch() משווה את הערך התווי לשמות הארגומנטים ומחזיר את התוצאה המתאימה.
  • נפילה הלאה (fall-through): שם שהצד הימני שלו ריק (sat = ,) נופל הלאה לתוצאה של המקרה הבא. כך "sat" ו-"sun" חולקים את "weekend" בלי לחזור עליו.
  • ברירת מחדל: הארגומנט האחרון ללא שם ("weekday") מוחזר כששום דבר לא מתאים. בלי ברירת מחדל, ערך שלא נמצאה לו התאמה גורם ל-switch() להחזיר NULL באופן בלתי נראה: הפונקציה שלכם מחזירה בשקט כלום, וזה באג מבלבל. תמיד ספקו ברירת מחדל (או הפכו אותה ל-stop() מפורש).

switch() זורח בתוך פונקציות שמנתבות לפי ארגומנט של מצב או שיטה; לכל דבר שמבוסס על ספים מספריים, הישארו עם else if או cut().

מה לקחת מכאן

  • if (condition) { } else { }: התנאי בסוגריים, ענף אחד רץ; שרשרו עם else if, ההתאמה הראשונה מנצחת.
  • בסקריפטים, כתבו } else { בשורה אחת: else בתחילת שורה הוא שגיאת תחביר.
  • if() צריך TRUE/FALSE אחד בדיוק: NA הוא שגיאה, וקטור ארוך יותר הוא שגיאה (מאז R 4.2). הגנו עם !is.na(x) &&, או צמצמו עם any()/all().
  • ifelse(test, yes, no) היא הגרסה הווקטורית: השתמשו בה כדי לחשב וקטורים חדשים, ואל תקננו אותה יותר מפעמיים.
  • switch() מטפל בניתוב לפי שמות, עם נפילה הלאה דרך מקרים ריקים. תמיד תנו לו ברירת מחדל.

בהמשך: לעשות משהו יותר מפעם אחת, לולאות for, ומתי לולאה היא (ומתי היא לא) הכלי הנכון.

שאלות נפוצות

איך כותבים משפט if else ב-R?

if (condition) { ... } else { ... }: התנאי בסוגריים עגולים וכל ענף בסוגריים מסולסלים. שרשרו בדיקות נוספות עם else if (condition). בסקריפט, else חייב להופיע באותה שורה של הסוגר המסולסל הסוגר של הענף הקודם (} else {), אחרת R מדווח unexpected 'else'.

מה ההבדל בין if ל-ifelse() ב-R?

if הוא משפט בקרת זרימה שבודק ערך TRUE/FALSE אחד בדיוק ומריץ ענף קוד אחד. ifelse(test, yes, no) היא פונקציה וקטורית: היא בודקת כל איבר בווקטור בבת אחת ומחזירה וקטור של תוצאות. השתמשו ב-if כדי להחליט מה התוכנית עושה; השתמשו ב-ifelse() כדי לחשב עמודה או וקטור חדשים מתוך קיימים.

למה R אומר 'the condition has length > 1'?

העברתם וקטור שלם ל-if(), שצריך TRUE או FALSE יחיד. מאז R 4.2 זו שגיאה ולא שימוש שקט באיבר הראשון. תקנו על ידי צמצום הווקטור לערך אחד, any(x > 5) או all(x > 5), או על ידי מעבר ל-ifelse() הווקטורי אם רציתם תוצאה לכל איבר.

איך switch() עובד ב-R?

switch(value, name1 = result1, name2 = result2, default) משווה ערך תווי לשמות הארגומנטים ומחזיר את התוצאה המתאימה. שם שהצד הימני שלו ריק נופל הלאה לתוצאה הבאה, כך שכמה מקרים יכולים לחלוק תוצאה אחת. הארגומנט האחרון ללא שם משמש כברירת מחדל; בלעדיו, ערך שלא נמצאה לו התאמה מחזיר NULL באופן בלתי נראה.

איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל