20

我想知道在某个索引处将向量分成两个的简单任务:

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)

4

3 回答 3

31

一个改进是:

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 <= 0pos >= length(x)stopifnot

于 2013-05-03T11:41:24.367 回答
7

我尝试使用弗洛德尔的答案,但在我的情况下它太慢了x(并且必须重复调用该函数)。所以我创建了以下函数,它更快,但也很丑陋并且行为不正常。特别是,它不会检查任何内容,并且至少会返回错误的结果pos >= length(x)or 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)
}

但是,使用长度为 10 6splitAt2的 x 运行速度大约快 20 倍:

library(microbenchmark)
W <- rnorm(1e6)
splits <- cumsum(rep(1e5, 9))
tm <- microbenchmark(
                     splitAt(W, splits),
                     splitAt2(W, splits),
                     times=10)
tm
于 2013-10-09T14:08:38.400 回答
4

另一种可能比弗洛德尔的解决方案更快和/或更可读/优雅的替代方案:

splitAt <- function(x, pos) {
  unname(split(x, findInterval(x, pos)))
}
于 2016-06-30T14:31:26.887 回答