在 R 中子集化一个未命名的向量

Subsetting an unnamed vector in R

我从一个函数中得到一个数字向量作为输出,我想删除所有高于 2900 的值,然后将余数直接传递给第二个函数。 (如果有帮助,它们将被排序。)有没有一种聪明的方法来做这个看似简单的事情,而不必停下来定义一个中间变量?

这是一种无需创建临时向量的方法。

  1. 函数 fg 是简单的测试函数,它们将整数序列从 1 输出到它们的参数 n。函数 gNA 分配给输出向量的一半。
  2. 函数 h 对其输入向量求和。
  3. 在管道的中间,有一个匿名函数,它对 fg 的输出进行子集化,并将结果向量通过管道传递给函数 h
  4. 对于来自 g 的管道,需要额外的代码来删除 NA,如果这是用户想要的。
f <- function(n) seq.int(n)
g <- function(n){
  y <- seq.int(n)
  is.na(y) <- sample(n, n/2)
  y
}
h <- function(x, na.rm = FALSE) sum(x, na.rm = na.rm)

set.seed(2022)
f(3000) |> (\(x) x[x <= 2900])() |> h()
#> [1] 4206450

set.seed(2022)
g(3000) |> (\(x) x[x <= 2900])() |> h()
#> [1] NA

set.seed(2022)
g(3000) |> (\(x) x[x <= 2900])() |> h(na.rm = TRUE)
#> [1] 2080026

set.seed(2022)
g(3000) |> (\(x) x[which(x <= 2900)])() |> h()
#> [1] 2080026

reprex package (v2.0.1)

于 2022 年 3 月 12 日创建

编辑

之后,输入可以通过管道传递给第一个函数,如下所示。

input <- 3000
input |> f() |> (\(x) x[x <= 2900])() |> h()
#> [1] 4206450

reprex package (v2.0.1)

于 2022 年 3 月 12 日创建

一个通用的预写函数让您可以在适当的时候通过管道传入和传出匿名向量。

vsubset <- function(v, condition) v[eval(str2expression(paste("v", condition)))]

1:10 %>% vsubset("<5")                                                                                                                                                                                                                        
# 1 2 3 4

为了暂时更容易理解,让我们制作三个更基本的版本:

equal_to <- function(v, equivalent) v[v == equivalent]
1:10 %>% equal_to(4)
# 4

less_than <- function(v, threshold) v[v < equivalent]
1:10 %>% less_than(4)
# 1 2 3

greater_than <- function(v, threshold) v[v > equivalent]
1:10 %>% less_than(4)
# 4 5 6 7 8 9 10

不过,我更喜欢只有一个 widely-applicable 功能。毕竟这三个很不完整:我们至少还需要<=>=!=.

为此,我们

  1. 将条件写成字符串(例如"==3"
  2. 使用 paste()
  3. 将其与矢量的 in-function 名称组合
  4. str2expression()
  5. 把字符串变成一个表达式
  6. 运行和eval()
  7. 的表达式

可能有比 eval(str2expression(paste(..))) 更有效的方法,但这对我有用。