我想在向量上使用过滤器列表。我的问题是,在此示例中,如何使用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
答案 0 :(得分:6)
这里有一些替代方法。全部仅使用基数R。(2)使用Reduce
。 (4)是具有最短代码。 (3)似乎特别简单。
1)外部,您实际上不需要Reduce
。如果应用于outer
的第j个元素的ith函数为TRUE,则使用my_vec
创建第ith行第j列为TRUE的逻辑矩阵,然后使用apply
创建一个逻辑矩阵。如果第j列中的所有元素都为TRUE,并且第一个下标为my_vec
,则其jth元素为TRUE的向量。
call_fun <- function(fun, x) fun(x)
my_vec[ apply(outer(filter_list, my_vec, Vectorize(call_fun)), 2, all) ]
## "AAafszx223" "AA232fiserf"
2)减少另一方面,我们当然可以使用Reduce
。创建一个使用字符串的函数,并使用filter_list
对Reduce
中的每个函数进行“与”运算并取结果。然后使用Filter
提取my_vec
的那些元素,该函数的应用为其提供TRUE。
Filter(function(x) Reduce(`&`, lapply(filter_list, do.call, list(x))), my_vec)
## [1] "AAafszx223" "AA232fiserf"
3)全部实际上,我们可以使用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)双重申请:此人使用了上述想法,但在使用双重sapply
时更加对称:
my_vec[ sapply(my_vec, function(x) all(sapply(filter_list, do.call, list(x)))) ]
## [1] "AAafszx223" "AA232fiserf"
答案 1 :(得分:4)
使用Reduce
的一种方法是:
my_vec[Reduce('&',lapply(filter_list,
function(f) {f(my_vec)}))]
答案 2 :(得分:2)
purrr
选项。
invoke_map
将函数列表作为第一个参数,并将这些函数映射到...
中的参数。
reduce('&')
返回一个TRUE
的向量,前提是LHS列表的向量中的所有对应条目均为TRUE
(与Reduce('&'
相同)。
keep(.x = vec, .p = logical_vec)
与vec[logical_vec]
相同。
-
library(purrr)
invoke_map(filter_list, x = my_vec) %>%
reduce(`&`) %>%
keep(.x = my_vec)
# [1] "AAafszx223" "AA232fiserf"
答案 3 :(得分:1)
另一个版本,尽管感觉像是G. Grothendieck的第一个答案:
library(magrittr)
sapply(filter_list, mapply, my_vec) %>% apply(., 1, all) %>% my_vec[.]
答案 4 :(得分:1)
一些选项:
library(purrr)
my_vec[reduce(map(filter_list, ~.(my_vec)), `&`)]
# [1] "AAafszx223" "AA232fiserf"
my_vec[reduce(filter_list, ~ .x & .y(my_vec), .init = TRUE)]
# [1] "AAafszx223" "AA232fiserf"
my_vec[apply(map_dfr(filter_list, ~.(my_vec)),1,all)]
# [1] "AAafszx223" "AA232fiserf"