Почему операторы ifelse R не могут возвращать векторы? - PullRequest
99 голосов
/ 26 августа 2009

Время от времени я считаю, что ifelse-заявления R довольно удобны. Например:

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

Это выбор дизайна, который выше моего paygrade?

Ответы [ 7 ]

80 голосов
/ 26 августа 2009

Документация для 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 {} конструкцию вместо этого.

60 голосов
/ 18 ноября 2009

Могу поспорить, что вам нужен простой оператор 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
10 голосов
/ 06 апреля 2018

Обратите внимание, что вы можете обойти проблему, если назначите результат внутри 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
9 голосов
/ 29 августа 2009

Да, я думаю, что ifelse () действительно предназначен для случаев, когда у вас большой длинный вектор тестов и вы хотите сопоставить каждый из двух вариантов. Например, я часто делаю цвета для plot () следующим образом:

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

Если у вас большой длинный вектор тестов, но вам нужны пары для выходов, вы можете использовать sapply() или plyr llply() или что-то еще, возможно.

3 голосов
/ 25 июля 2018

Вот подход, подобный предложенному Cath, но он может работать с существующими предварительно назначенными векторами

Он основан на использовании get() примерно так:

a <- c(1,2)
b <- c(3,4)
get(ifelse(TRUE, "a", "b"))
# [1] 1 2
3 голосов
/ 08 июля 2017

Иногда пользователю просто нужен оператор switch вместо ifelse. В этом случае:

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

(что является еще одним синтаксическим вариантом ответа Кена Уильямса)

0 голосов
/ 20 мая 2019

В вашем случае было бы полезно использовать 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...