Почему оператор 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