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

时间:2018-11-04 11:27:11

标签: r

首先,我简化我的问题。我想从数值向量中提取某些范围。例如,同时从1:20中提取3个范围:

  • 1
  • 8
  • 17

因此,预期输出为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 个答案:

答案 0 :(得分: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]
    }
)

答案 1 :(得分: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 :(得分: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

答案 3 :(得分: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