为什么R语言的ifelse语句不能返回向量?

155

有时候我发现R语言的ifelse语句非常实用。例如:

ifelse(TRUE,1,2)
# [1] 1
ifelse(FALSE,1,2)
# [1] 2

但是我对以下行为感到有些困惑。

ifelse(TRUE,c(1,2),c(3,4))
# [1] 1
ifelse(FALSE,c(1,2),c(3,4))
# [1] 3

这是一个超出我的权限范围的设计选择吗?


2
考虑到简单的if else语句可以正常工作,这种ifelse的设计有点奇怪。 - 2sb
5
ifelse是一个矢量化函数,它应该用于不同的任务。 - marbel
9个回答

125
ifelse函数的文档说明如下:

ifelse返回一个与test形状相同的值,该值填充了从yesno中选择的元素,具体取决于test的元素是TRUE还是FALSE

如果您传递长度为1的测试值,则会得到长度为1的结果。 如果您传递更长的测试向量,则会得到更长的结果。
> ifelse(c(TRUE, FALSE), c(1, 2), c(3, 4))
[1] 1 4

ifelse函数的特定目的是测试一组布尔值并返回一个与其长度相同的向量,填充的元素来自于(向量)yesno参数。

由于该函数名称的缘故,常常会产生混淆,实际上您只需要普通的if () {} else {}语句。


18
也许你在第二组语句中真正想要的是 if (TRUE) c(1,2) else c(3,4) - Jonathan Chang

78

我打赌你想要一个简单的if语句,而不是ifelse - 在R中,if不仅是控制流结构,它还可以返回一个值:

> if(TRUE) c(1,2) else c(3,4)
[1] 1 2
> if(FALSE) c(1,2) else c(3,4)
[1] 3 4

@Ken,这对我来说是有效的,尽管我得到了一个我需要的常量警告“" Warning in if (req(inputval) == "All") { : the condition has length > 1 and only the first element will be used"”,我该怎么做才能消除这个警告? - user5249203
1
@user5249203,问题和Ken的回答是针对条件为单个值的情况,即长度为1的向量。警告表明req(inputval)具有更多元素。要获取单个值,函数any()all()可能会有用。 - Uwe

17

请注意,如果您将结果分配在 ifelse 内部,则可以规避该问题:

ifelse(TRUE, a <- c(1,2), a <- c(3,4))
a
# [1] 1 2

ifelse(FALSE, a <- c(1,2), a <- c(3,4))
a
# [1] 3 4

4
依我之见,这鼓励人们滥用向量化的 ifelse() 函数来代替控制流程中的 if ... else ... 进行赋值。如果条件只有一个 TRUEFALSE 值,我更喜欢写成 a <- if (TRUE) c(1,2) else c(3,4)if (TRUE) a <- c(1,2) else a <- c(3,4) - Uwe
2
@Uwe,虽然我认为在单一条件情况下使用ifelse而不是ifelse可能不会对性能产生太大的影响,并且在某些情况下(这里只是简单猜测)可能更喜欢使用ifelse,但我不得不同意你的看法。我只是想展示一种使用ifelse的方式。 - Cath
你也可以稍微滥用 ifelselist - ifelse(TRUE, list(c(1,2)), list(c(3,4)) )[[1]] - thelatemail

15

使用 `if`,例如:

> `if`(T,1:3,2:4)
[1] 1 2 3

1
这是唯一一个可以实际提供ifelse预期功能的答案。 - sus_mlm
有没有关于 `if` 的网址? - Takuro Ikeda
@TakuroIkeda 请查看http://adv-r.had.co.nz/Functions.html - blueskyddd

9

是的,我认为ifelse()函数主要用于当你有一个长向量的测试,并想将每个测试映射到两个选项中之一。例如,我通常使用以下方式为plot()函数设置颜色:

plot(x,y, col = ifelse(x>2,  'red', 'blue'))

如果您有一个很长的测试向量,但想要成对的输出,可以使用sapply()plyrllply()等函数。

4
这里提供了一种与Cath建议类似的方法,但它可以与现有的预分配向量一起使用。该方法基于如下使用get():
a <- c(1,2)
b <- c(3,4)
get(ifelse(TRUE, "a", "b"))
# [1] 1 2

4
有时用户只需要使用switch语句,而不是ifelse语句。在这种情况下:
condition <- TRUE
switch(2-condition, c(1, 2), c(3, 4))
#### [1] 1 2

(这是Ken Williams的答案的另一种语法选项)

2
在您的情况下,使用dplyr中的if_else会很有帮助:if_elseifelse更严格,并且会为您的情况抛出错误:“最初的回答”。
library(dplyr)
if_else(TRUE,c(1,2),c(3,4))
#> `true` must be length 1 (length of `condition`), not 2

0

everydropr上发现:

ifelse(rep(TRUE, length(c(1,2))), c(1,2),c(3,4))
#>[1] 1 2

可以复制您的条件结果以返回所需的长度


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接