تابع switch() میتواند جایگزینی مختصر برای مجموعهای طولانی از شرطهای if ... else if باشد.
متغیری که روی آن سوئیچ انجام میشود معمولاً یک رشته است و در این صورت میتوان کوتیشنها را از انتخابگر حذف کرد.
star <- function(type) {
switch(type,
M = , # will "fall through" if no value given
K = "red dwarf",
G = "Earth-like",
"bigger star" # only correct for O,B,A,F
)
}
> star("M")
[1] "red dwarf"
توجه کنید که گزینهها فقط زمانی به گزینهی بعدی میرسند که مقدار خالی گذاشته شده باشد، مانند M در مثال بالا.
لازم نیست دستورهای break را مانند برخی زبانهای دیگر بگنجانید.
وقتی روی نوعهای character سوئیچ میکنید، مقدار نهایی یک پیشفرض است، همانطور که اینجا میبینید.
با نوعهای عدد صحیح، هیچ پیشفرضی نمیتوان داد.
dplyr
switch در R پایه نسبتاً محدود است: فقط تطبیق دقیق با یک ورودی واحد را انجام میدهد.
این در سال ۱۹۹۳ که R برای اولین بار منتشر شد معقول به نظر میرسید، اما برای استفادهی مدرن نیاز به بهبود دارد.
همانطور که در مفهوم Conditionals اشاره شد، مجموعهی بستههای tidyverse طوری طراحی شده است که قابلیتهای R پایه را تکمیل کند (و گاهی جایگزین آن شود) بدون اینکه سازگاری با نسخههای قبلی را تحت تأثیر قرار دهد.
بستهی dplyr را میتوان با افزودن library(dplyr) (برای همان بسته) یا library(tidyverse) (برای کل مجموعه) به بالای کدتان در دسترس قرار داد.
کتابخانهی dplyr دو تابع اضافی مرتبط با switch ارائه میدهد.
recode_values و replace_values
این دو تابع مرتبط امکان نگاشت برداری شبیه به switch را از مقادیر قدیمی به مقادیر جدید فراهم میکنند.
تفاوت اصلی آنها این است که recode_values() یک بردار کاملاً جدید میسازد، در حالی که replace_values() بهروزرسانی جزئی یک بردار موجود را ممکن میکند.
تطبیق همچنان دقیق است، اما:
~ به جای = به هم مرتبط میشوند.library(dplyr)
x <- c("a", "b", "a", "d", "b", NA, "c", "e", "z")
recode_values(
x,
"a" ~ 1,
"b" ~ 2,
"c" ~ 3,
c("d", "e") ~ 4, # either "d' or "e" will match
NA ~ 0, # matches missing values
default = 100 # note the different syntax for the default
)
#> [1] 1 2 1 4 2 0 3 4 100
case_when
case_when نحوهی نگارش case_match را یک مرحله فراتر میبرد و اجازه میدهد هر عبارت منطقی در سمت چپ ~ قرار بگیرد.
بردار ورودی (x در مثال زیر) به عنوان آرگومان ارائه نمیشود؛ فقط باید از قبل تعریف شده باشد.
x <- 1:10
case_when(
x < 3 ~ "low",
between(x, 3, 5) ~ "mid",
between(x, 6, 8) ~ "high",
.default = "what?"
)
#> [1] "low" "low" "mid" "mid" "mid" "high" "high" "high" "what?" "what?"
تابع between() نیز بخشی از dplyr است.
در این تمرین اولین نوبت یک بازی Blackjack را شبیهسازی میکنیم.
شما دو کارت دریافت میکنید و میتوانید کارت نمایان دیلر را ببینید. همهی کارتها با «رشته»ای مانند «ace»، «king»، «three»، «two» و غیره نمایش داده میشوند. ارزش هر کارت به این صورت است:
| کارت | ارزش | کارت | ارزش |
|---|---|---|---|
| ace | ۱۱ | eight | ۸ |
| two | ۲ | nine | ۹ |
| three | ۳ | ten | ۱۰ |
| four | ۴ | jack | ۱۰ |
| five | ۵ | queen | ۱۰ |
| six | ۶ | king | ۱۰ |
| seven | ۷ | other | ۰ |
نکته: معمولاً آسها میتوانند ارزش ۱ یا ۱۱ داشته باشند، اما برای سادگی فرض میکنیم که فقط ارزش ۱۱ را میگیرند.
بسته به دو کارت شما و کارت دیلر، برای اولین نوبت بازی یک استراتژی وجود دارد که در آن این گزینهها را دارید:
هرچند هنوز بهینه نیست، شما از استراتژیای پیروی میکنید که دوستتان Alex مشغول توسعهی آن بوده است؛ این استراتژی به شرح زیر است:
تابعی به نام parse_card پیادهسازی کنید که ارزش عددی یک کارت را محاسبه میکند:
parse_card("ace")
# => 11
تابعی به نام first_turn بنویسید که منطق تصمیمگیری را همانطور که در بالا توضیح داده شد پیادهسازی میکند:
first_turn(card1, card2, dealer_card)
در ادامه چند نمونه از نتایج مورد انتظار را میبینید:
first_turn("ace", "ace", "jack") == "P"
first_turn("ace", "king", "ace") == "S"
first_turn("five", "queen", "ace") == "H"