Чому не можна, якщо твердження R, повертати вектори?


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, враховуючи той факт, що простий, якщо ще працює.
2sb

4
ifelse - векторизована функція. Їх слід використовувати для різних завдань.
Марбель

Відповіді:


99

Документація для ifelseштатів:

ifelseповертає значення з тією ж формою, testяка заповнена з елементами , вибраними з яких yesабо в noзалежності від того , елемент testє 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"що мені робити, щоб позбутися цього попередження?
користувач5249203

1
@ user5249203, запитання та відповідь Кена відносяться до випадку, коли умова є єдиним значенням, тобто вектором довжини 1. Попередження вказує, що в ньому req(inputval)є більше елементів. Для отримання єдиного значення функції any()або all()можуть бути корисні.
Уве

12

Зауважте, що проблему можна обійти, якщо призначити результат всередині 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
@ Хоча я не думаю, що різниця в продуктивності при використанні ifelseзамість if... elseу випадку єдиної умови дійсно може бути проблемою і ifelseможе бути віддана перевагу в деяких випадках всередині коду (простий здогад тут), я не можу погодитися з вами ;-). Я просто хотів показати шлях ifelse.
Кат

9

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

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

Якщо у вас великий довгий вектор тестів , але хотів пар для виходів, ви можете використовувати sapply()або plyr«S llply()або що - то, можливо.


4

Іноді користувачеві просто потрібна switchзаява замість an ifelse. В такому разі:

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

(що є ще одним варіантом синтаксису відповіді Кена Вільямса)


4

Ось такий підхід, подібний до запропонованого Cath, але він може працювати з існуючими заздалегідь приписаними векторами

Він заснований на використанні get()подібного:

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_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

0

Знайдено на кожній підкладці :

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

Може повторити результат вашого стану, щоб повернути потрібну довжину

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.