从数字向量中提取多个范围

3
首先,我简化一下我的问题。我想从一个数字向量中提取特定的范围。例如,在同一时间从1:20中提取3个范围:

  • 1 < x < 5
  • 8 < x < 12
  • 17 < x < 20
因此,期望的输出是2, 3, 4, 9, 10, 11, 18, 19
我尝试使用函数findInterval()和控制参数rightmost.closedleft.open来实现这一点,但是任何参数设置都无法实现目标。
x <- 1:20
v <- c(1, 5, 8, 12, 17, 20)

x[findInterval(x, v) %% 2 == 1]
# [1]  1  2  3  4  8  9 10 11 17 18 19

x[findInterval(x, v, rightmost.closed = T) %% 2 == 1]
# [1]  1  2  3  4  8  9 10 11 17 18 19 20

x[findInterval(x, v, left.open = T) %% 2 == 1]
# [1]  2  3  4  5  9 10 11 12 18 19 20

顺便提一下,条件也可以像矩阵那样:
     [,1] [,2]
[1,]    1    5
[2,]    8   12
[3,]   17   20

如果不必要,我不想使用for循环。

非常感谢任何帮助。

4个回答

5

我可能会使用purrr :: map2或Map,将您的下限和上限作为参数传递,并使用自定义函数过滤数据集。

library(purrr)
x <- 1:20
lower_bounds <- c(1, 8, 17)
upper_bounds <- c(5, 12, 20)
map2(
    lower_bounds, upper_bounds, function(lower, upper) {
        x[x > lower & x < upper]
    }
)

4
您可以使用data.table::inrange和它的incbounds参数。假设范围在矩阵'm'中,如您的问题所示:
x[data.table::inrange(x, m[ , 1], m[ , 2], incbounds = FALSE)]
# [1]  2  3  4  9 10 11 18 19

 m <- matrix(v, ncol = 2, byrow = TRUE)

2

你已经走在了正确的道路上,left.open确实有帮助,但是rightmost.closed实际上只涉及到最后一个区间而不是每个区间的右侧。因此,我们需要使用两次left.open。正如你自己发现的那样,最佳的方法似乎是:

x[findInterval(x, v) %% 2 == 1 & findInterval(x, v, left.open = TRUE) %% 2 == 1]
# [1]  2  3  4  9 10 11 18 19

显然有其他选择。例如,

fun <- function(x, v)
  if(length(v) > 1) v[1] < x & x < v[2] | fun(x, v[-1:-2]) else FALSE
x[fun(x, v)]
# [1]  2  3  4  9 10 11 18 19

你的递归函数非常优秀。非常感谢! - Darren Tsai
1
我修改了你的代码:x[findInterval(x, v) %% 2 == 1 & findInterval(x, v, left.open = T) %% 2 == 1],并得到了同样的输出结果。怎么样? - Darren Tsai

1
我发现只需要使用sapply()就可以轻松完成:
x <- 1:20
v <- c(1, 5, 8, 12, 17, 20)
(v.df <- as.data.frame(matrix(v, 3, 2, byrow = T)))

  #   V1 V2
  # 1  1  5
  # 2  8 12
  # 3 17 20

y <- sapply(x, function(x){
  ind <- (x > v.df$V1 & x < v.df$V2)
  if(any(ind)) x else NA
})

y[!is.na(y)]
# [1]  2  3  4  9 10 11 18 19

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接