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


118

我发现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

这是我的薪水之上的设计选择吗?


1
鉴于ifelse简单有效的事实,ifelse的设计并不奇怪。
2012年

4
ifelse是向量化函数。它们应用于不同的任务。
2014年

Answers:


98

ifelse状态文档:

ifelse返回具有与形状相同的值,该值test填充有选自yesno的元素,具体取决于testis TRUE或元素FALSE

由于您通过的是长度为1的测试值,因此得到的是长度为1的结果。如果通过更长的测试向量,则将得到更长的结果:

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

因此ifelse,此特定目的是为了测试布尔向量,并返回相同长度的向量,并填充从(向量)yes和自no变量中提取的元素。

由于函数的名称,通常在真正只需要常规if () {} else {}构造的情况下使用它会引起混淆。


16
也许您真正想要的是第二组语句if (TRUE) c(1,2) else c(3,4)

69

我敢打赌,您想要一个简单的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()可能有用。
乌威'18

11

请注意,如果您在内分配结果,则可以避免该问题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

3
恕我直言,这鼓励滥用矢量化ifelse()功能代替if ... else ...分配控制流。如果条件是一个单一值TRUE或一个FALSE值,我希望编写a <- if (TRUE) c(1,2) else c(3,4)if (TRUE) a <- c(1,2) else a <- c(3,4)
-Uwe,

1
@Uwe虽然我不认为使用ifelse而不是if... 时的性能差异else确实是一个问题,并且ifelse在某些情况下在代码内部(在这里简单猜测)可能是首选,但我不能不同意;-)。我只是想展示一种方法ifelse
Cath

9

是的,我认为ifelse()确实是为有大量较长的测试向量并且想要将每个映射到两个选项之一而设计的。例如,我经常以这种方式为plot()上色:

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

如果你有一个测试的大长向量,但希望对为输出,你可以使用sapply()plyrllply()什么的,也许。


4

有时用户只需要一个switch语句而不是一个ifelse。在这种情况下:

condition <- TRUE
switch(2-condition, c(1, 2), c(3, 4))
#### [1] 1 2

(这是Ken Williams回答的另一个语法选项)


4

这是一种类似于Cath建议的方法,但是它可以与现有的预先分配的向量一起使用

它是基于使用get()like这样的:

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

4

使用`if`,例如

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

这是实际上可以提供ifelse预期功能的唯一答案。
sus_mlm

2

在您的情况下,使用if_elsefrom dplyr会有所帮助:if_else比严格ifelse,并且会为您的情况引发错误:

library(dplyr)
if_else(TRUE,c(1,2),c(3,4))
#> `true` must be length 1 (length of `condition`), not 2

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.