R 有一组和其他许多语言相同的运算符:
1 == 2 # FALSE
1 != 2 # TRUE
1 < 2 # TRUE
1 > 2 # FALSE
1 <= 2 # TRUE
1 >= 2 # FALSE
if-then-else 的基本形式如下:
if (x > 10) {
y <- "big"
} else if (x > 2) {
y <- "medium"
} else {
y <- "tiny"
}
在这种情况下,包裹布尔值的圆括号 ( ) 和包裹语句体的花括号 { } 都是必需的。
简单的if语句可以缩写:
if (x == 0) return("success")
提前看一下 vector-filtering 概念:括号()中的条件必须求值为单个TRUE/FALSE。
在比较中纳入向量通常会得到一个布尔值向量,所以需要用聚合函数把它们包起来,比如 all()(所有值都是TRUE吗?)或 any()(至少有一个值是TRUE吗?)。
numbers <- c(4,5,7,9,10,11)
numbers %% 3 == 0 # gives vector of booleans
#> [1] FALSE FALSE FALSE TRUE FALSE FALSE
# use any() to get a single TRUE/FALSE
if (any(numbers %% 3 == 0)) print("1 or more numbers are divisible by 3")
#> [1] "1 or more numbers are divisible by 3"
ifelse函数如果结果只有 true/false 两种情况,另一种 if-else 形式可能会很有用。
y <- ifelse(x > 8, "big", "small")
# Don't mix result types:
z <- ifelse(x > 100, 100, "small") # numeric or string result? Expect problems!
ifelse()正好接受三个形参:
TRUE时的值FALSE时的值。也可以传入向量,此时会产生向量输出。
在这种情况下,要确保两个分支得到的数据类型相同:数值、字符、逻辑等。
这会在 vector-functions 概念中介绍。
这两个结果(上面例子中的 "big", "small")应该是单个值。
遗憾的是,如果这里传入更长的向量,R 很可能会做出令人困惑、出乎意料的事情,而且不会给出任何警告信息。
if_else函数R 语言的维护者奉行尽量避免破坏性变更的策略。 这有助于维护 CRAN 中数量庞大的第三方包,但也限制了用现代编程概念更新 base R 的能力。
近年来,陆续出现了一些扩展、有时甚至取代 R 功能的包,它们基于数十年来对 R 原始设计优缺点的经验。
这些包组成了 tidyverse 集合。
它们于 2023 年被加入 Exercism 的测试运行器,你可以在练习中使用它们。
我们的 R 学习路径比 tidyverse 的加入早了几年,所以你可能会注意到,许多社区解答仍然只使用基础语言。
dplyr包dplyr主要用于操作数据框(课程后面会讲到)。
在代码开头用library(dplyr)加载它,或者用library(tidyverse)加载整个集合。
你可能会看到关于名称被遮蔽的警告信息,但这很少成为问题。
就目前这个概念而言,if_else函数值得一提。
它和 base R 中的 ifelse 大体相似。
library(dplyr) # warnings not shown
x <- 10
if_else(x > 8, "big", "small")
#> [1] "big"
主要区别在于,if_else可以多接受一个可选的第四个实参,用于处理 缺失 值,这类值在 R 中用 NA 表示。
xs <- c(3, NA, 10, NA, 4) # a 5-element vector
xs
#> [1] 3 NA 10 NA 4
if_else(xs > 8, "big", "small", "missing")
#> [1] "small" "missing" "big" "missing" "small"
# contrast:
ifelse(xs > 8, "big", "small")
#> [1] "small" NA "big" NA "small"
你可能还会发现,if_else的错误信息比旧的ifelse好得多。
加载dplyr库之后,你还可以使用 between() 函数。
R 不允许串联比较,所以1 <= x <= 5会给出错误信息。
加载dplyr后,between(x, 1, 5)等价于x >= 1 & x <= 5,而且可能更易读。
上下限都包含在内。