lapply 和 ifelse 不能按预期工作
lapply and ifelse together not working as expected
我正在写一个关于 R 的文档,我想出了一个我无法理解的例子。让我们这样说:
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]]))
我本以为我的列表中的数字元素是 2-folded 而字符向量保持原样。相反,列表中数字元素的结果只是每个元素的第一个组成部分,就好像 ifelse 的 TRUE 条件(即 1)接管了 lapply 的 x 索引一样。谁能告诉我这背后的逻辑,我应该输入什么?
非常感谢。
最好,
大卫
1) if 我们这里要if
,而不是ifelse
。也简化了代码。
f <- function(x) if (is.numeric(x)) x*2 else x
lapply(mylist, f)
给予:
[[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 尽管在这种情况下这可能有点太复杂而无法保证,但如果我们有更大的 类 集合,它可能会有用,它是还表明这可以在没有任何 if
使用 S3 的情况下完成。为此,我们定义了一个带有数字和默认方法的 S3 泛型,然后 S3 将自动分派适当的方法。
dble <- function(x, ...) UseMethod("dble")
dble.numeric <- function(x, ...) 2 * x
dble.default <- function(x, ...) x
lapply(mylist, dble)
3) tryCatch 另一种不使用 if
的方法是将参数加倍,如果它引发错误则捕获它。同样,在这种情况下这可能太复杂而无法保证,但它说明了如果实际情况更复杂可以做什么。
f2 <- function(x) tryCatch(2 * x, error = function(e) x)
lapply(mylist, f2)
4) rrapply rrapply包中的rrapply
函数可以指定一个条件,使得该函数只应用于满足它的元素。
library(rrapply)
rrapply(mylist, is.numeric, function(x) 2 * x)
5) modify_if purrr 包还有一个函数,它只会修改满足条件的元素。
library(purrr)
modify_if(mylist, is.numeric, `*`, 2)
问题是条件只创建一个 TRUE
,而是尝试这样的事情:
#Code
lapply(1:length(mylist),
function(x) ifelse(lapply(mylist[[x]],is.numeric),
mylist[[x]]*2, mylist[[x]]))
问题是矩阵结构会丢失,所以@G.Grothendieck的答案会是更好的选择。
我正在写一个关于 R 的文档,我想出了一个我无法理解的例子。让我们这样说:
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]]))
我本以为我的列表中的数字元素是 2-folded 而字符向量保持原样。相反,列表中数字元素的结果只是每个元素的第一个组成部分,就好像 ifelse 的 TRUE 条件(即 1)接管了 lapply 的 x 索引一样。谁能告诉我这背后的逻辑,我应该输入什么? 非常感谢。 最好, 大卫
1) if 我们这里要if
,而不是ifelse
。也简化了代码。
f <- function(x) if (is.numeric(x)) x*2 else x
lapply(mylist, f)
给予:
[[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 尽管在这种情况下这可能有点太复杂而无法保证,但如果我们有更大的 类 集合,它可能会有用,它是还表明这可以在没有任何 if
使用 S3 的情况下完成。为此,我们定义了一个带有数字和默认方法的 S3 泛型,然后 S3 将自动分派适当的方法。
dble <- function(x, ...) UseMethod("dble")
dble.numeric <- function(x, ...) 2 * x
dble.default <- function(x, ...) x
lapply(mylist, dble)
3) tryCatch 另一种不使用 if
的方法是将参数加倍,如果它引发错误则捕获它。同样,在这种情况下这可能太复杂而无法保证,但它说明了如果实际情况更复杂可以做什么。
f2 <- function(x) tryCatch(2 * x, error = function(e) x)
lapply(mylist, f2)
4) rrapply rrapply包中的rrapply
函数可以指定一个条件,使得该函数只应用于满足它的元素。
library(rrapply)
rrapply(mylist, is.numeric, function(x) 2 * x)
5) modify_if purrr 包还有一个函数,它只会修改满足条件的元素。
library(purrr)
modify_if(mylist, is.numeric, `*`, 2)
问题是条件只创建一个 TRUE
,而是尝试这样的事情:
#Code
lapply(1:length(mylist),
function(x) ifelse(lapply(mylist[[x]],is.numeric),
mylist[[x]]*2, mylist[[x]]))
问题是矩阵结构会丢失,所以@G.Grothendieck的答案会是更好的选择。