我想知道在某个索引处将矢量分成两个的简单任务:
splitAt <- function(x, pos){
list(x[1:pos-1], x[pos:length(x)])
}
a <- c(1, 2, 2, 3)
> splitAt(a, 4)
[[1]]
[1] 1 2 2
[[2]]
[1] 3
我的问题:必须有一些现有的功能,但我找不到它?可能split
可能吗?如果pos=0
或pos>length(a)
。
答案 0 :(得分:26)
改进将是:
splitAt <- function(x, pos) unname(split(x, cumsum(seq_along(x) %in% pos)))
现在可以采用位置向量:
splitAt(a, c(2, 4))
# [[1]]
# [1] 1
#
# [[2]]
# [1] 2 2
#
# [[3]]
# [1] 3
如果pos <= 0
或pos >= length(x)
在单个列表项中返回整个原始向量的意义上确实正确(主观)。如果您希望错误输出,请使用功能顶部的stopifnot
。
答案 1 :(得分:5)
我尝试使用flodel's answer,但在我的情况下使用非常大的x
太慢了(并且必须重复调用该函数)。所以我创建了以下功能,这个功能更快,但也非常难看并且行为不正常。特别是,它不会检查任何内容,并且至少会为pos >= length(x)
或pos <= 0
返回错误结果(如果您不确定输入并且不太关心速度,可以自己添加这些检查) ,也许还有其他一些案例,所以要小心。
splitAt2 <- function(x, pos) {
out <- list()
pos2 <- c(1, pos, length(x)+1)
for (i in seq_along(pos2[-1])) {
out[[i]] <- x[pos2[i]:(pos2[i+1]-1)]
}
return(out)
}
但是,splitAt2
运行速度快20倍,x长度为10 6 :
library(microbenchmark)
W <- rnorm(1e6)
splits <- cumsum(rep(1e5, 9))
tm <- microbenchmark(
splitAt(W, splits),
splitAt2(W, splits),
times=10)
tm
答案 2 :(得分:2)
另一种可能比flodel's solution更快和/或更具可读性/优雅的替代方案:
splitAt <- function(x, pos) {
unname(split(x, findInterval(x, pos)))
}