Почему оператор R ifelse не может возвращать векторы?
Я обнаружил, что 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
возвращает значение с той же формой, что и у test
которое заполнено элементами, выбранными из yes
или no
зависимости от того, является ли элемент test
TRUE
или FALSE
.
Поскольку вы передаете тестовые значения длины 1, вы получаете результаты длины 1. Если вы пропустите более длинные тестовые векторы, вы получите более длинные результаты:
> ifelse(c(TRUE, FALSE), c(1, 2), c(3, 4))
[1] 1 4
Таким образом, ifelse
предназначен для конкретной цели тестирования вектора логических значений и возврата вектора такой же длины, заполненного элементами, взятыми из аргументов (vector) yes
и no
.
Из-за имени функции часто возникает путаница, когда вы хотите использовать обычную конструкцию if() {} else {}
.
Ответ 2
Я уверен, вы хотите, чтобы простая инструкция 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
Ответ 3
Обратите внимание, что вы можете обойти проблему, если назначите результат внутри 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() действительно предназначен для тех случаев, когда у вас большой длинный вектор тестов и вы хотите сопоставить каждый из двух вариантов. Например, я часто делаю цвета для plot() следующим образом:
plot(x,y, col = ifelse(x>2, 'red', 'blue'))
Если у вас был большой длинный вектор тестов, но нужны пары для выходов, вы могли бы использовать sapply()
или plyr
llply()
или что-то, возможно.
Ответ 5
Иногда пользователю просто нужен оператор switch
вместо ifelse
. В этом случае:
condition <- TRUE
switch(2-condition, c(1, 2), c(3, 4))
#### [1] 1 2
(это еще один вариант синтаксиса ответа Кен Уильямса)
Ответ 6
Вот подход, аналогичный тому, который предложен Кэт, но он может работать с существующими предварительно назначенными векторами
Он основан на использовании get()
примерно так:
a <- c(1,2)
b <- c(3,4)
get(ifelse(TRUE, "a", "b"))
# [1] 1 2
Ответ 7
В вашем случае было бы полезно использовать if_else
из 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
Ответ 8
используйте "если", например
> 'if'(T,1:3,2:4)
[1] 1 2 3