Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
175 views
in Technique[技术] by (71.8m points)

r - Weird that `ifelse` is not always the simple form of `if`

Just met a weird situation that ifelse changes the result.

My intention is to decide if the image is load properly, if yes, stay what it is, if not, load the image, assuming the path is correct.

but it doesn''t work. The result becomes a single value, instead of image expected.

Please find the toy sample for better picture.

library(imager)

# save boats in JPG form
save.image(boats, file = "boatsJPG.jpg")

# test -1

im <- boats
class(im)
#[1] "cimg"         "imager_array" "numeric"  

im = ifelse(any(class(im) %in% "cimg"), im, boats)
class(im)
#[1] "numeric"


# test -2
im <- "boatsJPG.jpg"
class(im)
#[1] "character"
im = ifelse(any(class(im) %in% "cimg"), im, load.image(im))

class(im)
#[1] "numeric"

On the other hand, the sample works

im <- boats
if(!any(class(im) %in% "cimg")) {im <- load.image(im)}

class(im)
#[1] "cimg"         "imager_array" "numeric"  


im <- "boatsJPG.jpg"
if(!any(class(im) %in% "cimg")) {im <- load.image(im)}

class(im)
#[1] "cimg"         "imager_array" "numeric"  

How come? Please advise.

question from:https://stackoverflow.com/questions/66051571/weird-that-ifelse-is-not-always-the-simple-form-of-if

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The whole point of ifelse, in contrast to if, is that it’s vectorised: its result will be of the same length as the test. Since your test expression is of length 1 (= a single value), so will the result be a singe value. In addition, ifelse strips attributes (including the class)1. According to the documentation:

The mode of the result may depend on the value of ‘test’ (see the examples), and the class attribute (see ‘oldClass’) of the result is taken from ‘test’ and may be inappropriate for the values selected from ‘yes’ and ‘no’.

See also the examples there.

The only reason to use ifelse is when you specifically want vectorisation. For a single test value, use if. The idiomatic way of writing this in R would be as follows:

if (inherits(im, 'cimg')) im = boats

Or maybe:

im = if (inherits(im, 'cimg') im else boats

There are two additional things of note in this code:

  1. x %in% 'foo' is the same as x == 'foo'. Using %in% here is unnecessary and confusing (because %in% implies that we’re matching x against a vector of more than one values).
  2. It’s virtually always better to use inherits for the test you’re trying to perform, rather than manually checking the value of class.

1 In my opinion that’s a defect (even though it’s documented). And others clearly agree, which is why if_else in ‘dplyr’ behaves sensibly.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...