Функція switch() може стати лаконічною заміною довгій низці перевірок if ... else if.
Змінна, за якою відбувається перемикання, найчастіше є рядком тексту (англ. string), і в такому разі лапки в селекторі можна опустити.
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 уперше вийшов 1993 року, але для сучасного використання його треба вдосконалити.
Як зазначено в концепції 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.
У цій вправі ми змоделюємо перший хід гри в блекджек.
Ми отримаємо дві карти й зможемо побачити відкриту карту дилера. Усі карти подаються у вигляді рядка тексту (англ. string), наприклад "ace", "king", "three", "two" тощо. Значення кожної карти такі:
| карта | значення | карта | значення |
|---|---|---|---|
| ace | 11 | eight | 8 |
| two | 2 | nine | 9 |
| three | 3 | ten | 10 |
| four | 4 | jack | 10 |
| five | 5 | queen | 10 |
| six | 6 | king | 10 |
| seven | 7 | other | 0 |
Примітка: Зазвичай тузи можуть мати значення 1 або 11, але для простоти ми припустимо, що вони можуть мати лише значення 11.
Залежно від наших двох карт і карти дилера, для першого ходу гри існує стратегія, у якій ми маємо такі варіанти:
Хоча вона ще не оптимальна, ми дотримаємося стратегії, яку розробляє наш друг Алекс. Вона така:
Реалізувати функцію 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"
Зареєструйтеся на Exercism, щоб вивчати й опановувати R, а також 21 концепція111 вправ та справжнє наставництво від людей, і все це безкоштовно.