Mengapa pernyataan ifelse R tidak dapat mengembalikan vektor?

118

Saya telah menemukan pernyataan ifelse R cukup berguna dari waktu ke waktu. Sebagai contoh:

ifelse(TRUE,1,2)
# [1] 1
ifelse(FALSE,1,2)
# [1] 2

Tapi saya agak bingung dengan perilaku berikut.

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

Apakah ini pilihan desain di atas tingkat pembayaran saya?

Christopher DuBois
sumber
1
desain aneh kecil untuk ifelse mengingat fakta bahwa sederhana jika lain berfungsi.
2sb
4
ifelse adalah fungsi vektor. Mereka harus digunakan untuk tugas yang berbeda.
marbel

Jawaban:

99

Dokumentasi untuk ifelsenegara bagian:

ifelsemengembalikan nilai dengan bentuk yang sama seperti testyang diisi dengan elemen yang dipilih dari salah satu yesatau nobergantung pada apakah elemen dari testis TRUEatau FALSE.

Karena Anda melewati nilai tes panjang 1, Anda mendapatkan hasil panjang 1. Jika Anda melewati vektor uji yang lebih panjang, Anda akan mendapatkan hasil yang lebih panjang:

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

Jadi ifelsedimaksudkan untuk tujuan khusus menguji vektor boolean dan mengembalikan vektor dengan panjang yang sama, diisi dengan elemen yang diambil dari (vektor) yesdan noargumen.

Ini adalah kebingungan umum, karena nama fungsinya, untuk menggunakan ini ketika Anda sebenarnya hanya menginginkan if () {} else {}konstruksi normal .

Nathan Kitchen
sumber
16
Mungkin yang sebenarnya Anda inginkan dari rangkaian pernyataan kedua adalah if (TRUE) c(1,2) else c(3,4).
Jonathan Chang
69

Saya yakin Anda menginginkan ifpernyataan sederhana daripada ifelse- di R, ifbukan hanya struktur aliran kontrol, ini dapat mengembalikan nilai:

> 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 Williams
sumber
@Ken, ini berfungsi untuk saya, meskipun saya mendapatkan apa yang saya butuhkan peringatan terus-menerus " Warning in if (req(inputval) == "All") { : the condition has length > 1 and only the first element will be used"apa yang harus saya lakukan untuk menyingkirkan peringatan ini?
pengguna5249203
1
@ user5249203, pertanyaan dan jawaban Ken mengacu pada kasus di mana kondisinya adalah nilai tunggal, yaitu vektor dengan panjang 1. Peringatan menunjukkan bahwa req(inputval)memiliki lebih banyak elemen. Untuk mendapatkan satu nilai fungsi any()atau all()mungkin berguna.
Uwe
12

Perhatikan bahwa Anda dapat menghindari masalah jika Anda menetapkan hasilnya di dalam 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
Cath
sumber
3
IMHO, ini mendorong untuk menyalahgunakan ifelse()fungsi vektor di tempat aliran kontrol if ... else ...untuk tugas. Jika kondisinya adalah satu TRUEatau FALSEnilai, saya lebih suka menulis a <- if (TRUE) c(1,2) else c(3,4)atauif (TRUE) a <- c(1,2) else a <- c(3,4)
Uwe
1
@Uwe meskipun saya tidak berpikir perbedaan kinerja saat menggunakan ifelsealih-alih if... elsedalam kasus satu kondisi benar-benar dapat menjadi masalah dan ifelsemungkin lebih disukai dalam beberapa kasus di dalam kode (tebakan sederhana di sini), saya tidak setuju dengan Anda ;-). Saya hanya ingin menunjukkan jalan dengan ifelse.
Cath
9

ya, saya pikir ifelse () benar-benar dirancang untuk saat Anda memiliki vektor pengujian yang besar dan ingin memetakan masing-masing ke salah satu dari dua opsi. Misalnya, saya sering membuat warna untuk plot () dengan cara ini:

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

Jika Anda memiliki vektor panjang besar tes tetapi ingin pasang untuk output, Anda bisa menggunakan sapply()atau plyrs' llply()atau sesuatu, mungkin.

Brendan OConnor
sumber
4

Terkadang pengguna hanya membutuhkan switchpernyataan, bukan ifelse. Dalam hal itu:

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

(yang merupakan opsi sintaks lain dari jawaban Ken Williams)

agenis
sumber
4

Berikut adalah pendekatan yang serupa dengan yang disarankan oleh Cath, tetapi dapat bekerja dengan vektor yang telah ditetapkan sebelumnya

Ini didasarkan pada penggunaan get()seperti:

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

gunakan `if`, mis

> `if`(T,1:3,2:4)
[1] 1 2 3
blueskyddd.dll
sumber
Ini adalah satu-satunya jawaban di sini yang benar-benar dapat memberikan fungsionalitas ifelse yang diharapkan.
sus_mlm
2

Dalam kasus Anda, menggunakan if_elsefrom dplyrakan sangat membantu: if_elselebih ketat daripada ifelse, dan menimbulkan kesalahan untuk kasus Anda:

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

Ditemukan di everydropr :

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

Dapat mereplikasi hasil kondisi Anda untuk mengembalikan panjang yang diinginkan

SJGD
sumber