Reputation: 131
I am writing a doc about R and I've come up with an example that I cannot understand. Let us say this:
mylist <- list(8, 1:10, c(4,7,25), matrix(1:30, ncol = 5), "my name is not Donald")
lapply(1:length(mylist), function(x) ifelse(is.numeric(mylist[[x]]),
mylist[[x]]*2, mylist[[x]]))
I would have expected the numeric elements in my list to be 2-folded and the character vector to be left a it is. Instead, the result for numeric elements in the list is just the first component of each element, as if the ifelse's TRUE condition (i.e. 1) had taken over the lapply's x index. Could anybody please tell me the logic behind this, and what should I have typed instead? Thanks a lot. Best, David
Upvotes: 1
Views: 224
Reputation: 269421
1) if We want if
, not ifelse
here. Have also simplified the code a bit.
f <- function(x) if (is.numeric(x)) x*2 else x
lapply(mylist, f)
giving:
[[1]]
[1] 16
[[2]]
[1] 2 4 6 8 10 12 14 16 18 20
[[3]]
[1] 8 14 50
[[4]]
[,1] [,2] [,3] [,4] [,5]
[1,] 2 14 26 38 50
[2,] 4 16 28 40 52
[3,] 6 18 30 42 54
[4,] 8 20 32 44 56
[5,] 10 22 34 46 58
[6,] 12 24 36 48 60
[[5]]
[1] "my name is not Donald"
2) S3 Although this is probably a bit too complex to warrant in this case it could be useful if we had a larger set of classes and it is also shows that this could be done without any if
using S3. To do that we define an S3 generic with numeric and default methods and then S3 will automatically dispatch the appropriate method.
dble <- function(x, ...) UseMethod("dble")
dble.numeric <- function(x, ...) 2 * x
dble.default <- function(x, ...) x
lapply(mylist, dble)
3) tryCatch Another way which does not use if
is to double the argument and if it raises an error catch it. Again this is probably too complex to warrant in this case but it illustrates what could be done if the actual situation were more complex.
f2 <- function(x) tryCatch(2 * x, error = function(e) x)
lapply(mylist, f2)
4) rrapply The rrapply
function in the rrapply package can specify a condition such that the function is only applied to the elements satisfying it.
library(rrapply)
rrapply(mylist, is.numeric, function(x) 2 * x)
5) modify_if The purrr package also has a function that will modify only elements that satisfy a condition.
library(purrr)
modify_if(mylist, is.numeric, `*`, 2)
Upvotes: 5
Reputation: 39585
The issue is that the condition is only creating one TRUE
, instead try something like this:
#Code
lapply(1:length(mylist),
function(x) ifelse(lapply(mylist[[x]],is.numeric),
mylist[[x]]*2, mylist[[x]]))
The issue is that the matrix structure will be lost, so the answer from @G.Grothendieck would be a better option.
Upvotes: 0