首页 > 解决方案 > 使用 Reduce 调用函数列表

问题描述

我想在向量上使用过滤器列表。我的问题是,在此示例中,如何使用 Reduce(或其他基本 R 标准函数)来执行递归函数正在执行的操作(=在filter_list和逻辑与连接中应用所有函数):

my_vec <- c("AAffff1", "AAafszx223", "AAasfe2XX", "uuse3", "AA232fiserf", "ffse1211", "766", "AA33")

filter_list <- list(
  f_1 = function(x) {substr(x, 1, 2) == "AA"},
  f_2 = function(x) {grepl("\\d{3,}", x)},
  f_3 = function(x) {nchar(x) >= 5})

my_call <- function(fun_list, x) {
  if (length(fun_list) == 1) {
    fun_list[[1]](x) 
  } else {
    my_call(fun_list[-length(fun_list)], x) & fun_list[[length(fun_list)]](x)
  }
}
my_vec[my_call(filter_list, my_vec)]
# [1] "AAafszx223"  "AA232fiserf" --> ok

my_vec[Reduce(function(f, ...) f(...), filter_list, my_vec, right = TRUE)]
# character(0) --> wrong

标签: rfilter

解决方案


这里有一些替代方案。所有都只使用基数 R。 (2) 使用Reduce. (4) 是具有最短代码的。(3) 看起来特别简单。

1)外部你实际上并不需要Reduce这个。如果outer应用于第 j 个元素的第 i 个函数my_vec为 TRUE,则用于创建其第 i 行和第 j 列为 TRUE 的逻辑矩阵,然后如果第 j 列中的所有元素为 TRUE,则apply用于创建其第 j 个元素为 TRUE 的逻辑向量最后下标my_vec

call_fun <- function(fun, x) fun(x)
my_vec[ apply(outer(filter_list, my_vec, Vectorize(call_fun)), 2, all) ]
## "AAafszx223"  "AA232fiserf"

2) Reduce另一方面,我们当然可以使用Reduce. 创建一个函数,该函数接受一个字符串并filter_list使用Reduceto AND 结果调用其中的每个函数。然后用于提取那些应用该函数给出 TRUEFilter的元素。my_vec

Filter(function(x) Reduce(`&`, lapply(filter_list, do.call, list(x))), my_vec)
## [1] "AAafszx223"  "AA232fiserf"

3) all 实际上我们可以通过使用几乎相同的代码来消除Reduce(2) 中的问题。all

Filter(function(x) all(sapply(filter_list, do.call, list(x))), my_vec)
## [1] "AAafszx223"  "AA232fiserf"

4)另一个变体如下。sapply创建一个类似但从 (1) 中的矩阵转置的矩阵,然后我们将其应用于all其行和下标。

my_vec[ apply(sapply(filter_list, do.call, list(my_vec)), 1, all) ]
[1] "AAafszx223"  "AA232fiserf"

5) double sapply这个使用了上面的想法,但在使用 double 时更加对称sapply

my_vec[ sapply(my_vec, function(x) all(sapply(filter_list, do.call, list(x)))) ]
## [1] "AAafszx223"  "AA232fiserf"

推荐阅读