英文:
How to consecutively concatenate a vector of integers in R
问题
    vec <- c(1, 3, 2, 37)
我想要按顺序连接这个向量,使输出看起来类似于这样:
    > output
    [[1]]
    [1] 1
    
    [[2]]
    [1] 1 3
    
    [[3]]
    [1] 1 3 2
    
    [[4]]
    [1] 1 3 2 37
我写了一个函数来做到这一点,但它没有给我正确的输出:
    myfun <- function(vec){
      output = vector("list", length(vec))
      output[[1]] = vec[1]
      for(i in 2:length(vec)){
        output[[i]] = paste(output[[i - 1]], vec[i])
        output[[i]] = as.numeric(strsplit(output[[i]], " ")[[1]])
      }
      return(output)
    }
    > myfun(c(1, 3, 2, 37))
    [[1]]
    [1] 1
    
    [[2]]
    [1] 1 3
    
    [[3]]
    [1] 1 2
    
    [[4]]
    [1]  1 37
英文:
vec <- c(1, 3, 2, 37)
I want to consecutively concatenate this vector such that the output looks something like this:
> output
[[1]]
[1] 1
[[2]]
[1] 1 3
[[3]]
[1] 1 3 2
[[4]]
[1] 1 3 2 37
I wrote a function to do this, but it didn't give me the correct output:
myfun <- function(vec){
  output = vector("list", length(vec))
  output[[1]] = vec[1]
  for(i in 2:length(vec)){
    output[[i]] = paste(output[[i - 1]], vec[i])
    output[[i]] = as.numeric(strsplit(output[[i]], " ")[[1]])
  }
  return(output)
}
> myfun(c(1, 3, 2, 37))
[[1]]
[1] 1
[[2]]
[1] 1 3
[[3]]
[1] 1 2
[[4]]
[1]  1 37
答案1
得分: 5
A direct way to do this would be Reduce:
Reduce(f = c, x = vec, accumulate = TRUE)
There's a purrr::accumulate function that will accomplish the same thing:
purrr::accumulate(.x = vec, .f = c, .simplify = FALSE)
(Edited to incorporate the comment to just use c() as the function, much simpler.)
英文:
A direct way to do this would be Reduce:
Reduce(f = c,x = vec,accumulate = TRUE)
There's a purrr::accumulate function what will accomplish the same thing:
purrr::accumulate(.x = vec,.f = c,.simplify = FALSE)
(Edited to incorporate the comment to just use c() as the function, much simpler.)
答案2
得分: 4
我们可以使用 `lapply` 和 `head`(或 `[`) 来实现:
```r
lapply(seq_along(vec), head, x = vec)
# [[1]]
# [1] 1
# [[2]]
# [1] 1 3
# [[3]]
# [1] 1 3 2
# [[4]]
# [1]  1  3  2 37
seq_along(vec)类似于1:length(vec)(我们也可以使用这个,但在一些特殊情况下,seq_along更安全);- 当 
lapply被传递一个函数时,它通常会调用它一次,第一个参数包含值(这将是 1 到 4,依次递增);由于我们包括了x=vec(这是head的第一个参数),因此lapply将数字作为下一个参数应用于head,这恰好是n=。 
我们也可以使用 lapply(seq_along(vec), function(z) vec[1:z]) 来实现。
编辑:后者(vec[1:z] 的实现)比使用 head 要快得多,我应该知道这一点。
bench::mark(
  a1=lapply(seq_along(vec), head, x = vec),
  a2=lapply(seq_along(vec), function(z) vec[1:z]), 
  a3=lapply(1:length(vec), function(z) vec[1:z]),
  b=Reduce(f = c,x = vec,accumulate = TRUE),
  iterations = 100000)
# # 一个 tibble: 4 × 13
#   expression      min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time result     memory     time      
#   <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm> <list>     <list>     <list>    
# 1 a1          11.51µs  16.14µs    53800.        0B     3.23 99994     6      1.86s <list [4]> <Rprofmem> <bench_tm>
# 2 a2           2.95µs   4.06µs   215605.        0B     4.31 99998     2    463.8ms <list [4]> <Rprofmem> <bench_tm>
# 3 a3           3.04µs   4.01µs   221482.        0B     2.21 99999     1    451.5ms <list [4]> <Rprofmem> <bench_tm>
# 4 b            3.42µs    4.3µs   209810.        0B     4.20 99998     2   476.61ms <list [4]> <Rprofmem> <bench_tm>
# # ℹ 1 more variable: gc <list>
英文:
We can use lapply and head (or [) for this:
lapply(seq_along(vec), head, x = vec)
# [[1]]
# [1] 1
# [[2]]
# [1] 1 3
# [[3]]
# [1] 1 3 2
# [[4]]
# [1]  1  3  2 37
seq_along(vec)is analogous to1:length(vec)(and we can use that too, butseq_alongis safer in corner-cases);- when 
lapplyis given a function, it normally calls it once with the first argument containing the value (which will be 1 through 4, consecutively); since we includex=vec(which is the first argument ofhead), thenlapplyapplies the number as the next argument tohead, which happens to ben=. 
We could also have done lapply(seq_along(vec), function(z) vec[1:z]).
Edit: the latter (vec[1:z] implementation) is significantly faster than using head, I should have known that.
bench::mark(
  a1=lapply(seq_along(vec), head, x = vec),
  a2=lapply(seq_along(vec), function(z) vec[1:z]), 
  a3=lapply(1:length(vec), function(z) vec[1:z]),
  b=Reduce(f = c,x = vec,accumulate = TRUE),
  iterations = 100000)
# # A tibble: 4 × 13
#   expression      min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time result     memory     time      
#   <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm> <list>     <list>     <list>    
# 1 a1          11.51µs  16.14µs    53800.        0B     3.23 99994     6      1.86s <list [4]> <Rprofmem> <bench_tm>
# 2 a2           2.95µs   4.06µs   215605.        0B     4.31 99998     2    463.8ms <list [4]> <Rprofmem> <bench_tm>
# 3 a3           3.04µs   4.01µs   221482.        0B     2.21 99999     1    451.5ms <list [4]> <Rprofmem> <bench_tm>
# 4 b            3.42µs    4.3µs   209810.        0B     4.20 99998     2   476.61ms <list [4]> <Rprofmem> <bench_tm>
# # ℹ 1 more variable: gc <list>
答案3
得分: 1
我无法想到比Reduce(由@joran)或lapply(由@r2evans)更好的解决方案,它们已经足够高效和简洁。
以下是另一个基本的R选项,只是为了好玩:
> split(vec[(k <- sequence(seq_along(vec)))], cumsum(k == 1))
$`1`
[1] 1
$`2`
[1] 1 3
$`3`
[1] 1 3 2
$`4`
[1]  1  3  2 37
英文:
I cannot think of better solutions than Reduce (by @joran) or lapply (by @r2evans), which are already sufficiently efficient and concise.
Here is another base R option but just for fun
> split(vec[(k <- sequence(seq_along(vec)))], cumsum(k == 1))
$`1`
[1] 1
$`2`
[1] 1 3
$`3`
[1] 1 3 2
$`4`
[1]  1  3  2 37
答案4
得分: 0
如果这样做的原因是为了以后可以迭代列表,例如计算总和:
L <- list(vec[1], vec[1:2], vec[1:3], vec[1:4])
sapply(L, sum)
## [1]  1  4  6 43
那么我们可以通过使用rollapplyr来避免首先创建L:
library(zoo)
rollapplyr(vec, seq_along(vec), sum)  # 相同结果但没有中间列表L
## [1]  1  4  6 43
注意
从问题中提取的vec:
vec <- c(1, 3, 2, 37)
英文:
If the reason to do this is so that you can iterate over the list later taking, for example, sums
L <- list(vec[1], vec[1:2], vec[1:3], vec[1:4])
sapply(L, sum)
## [1]  1  4  6 43
then we can avoid creating L in the first place by using rollapplyr:
library(zoo)
rollapplyr(vec, seq_along(vec), sum)  # same but no intermediate L
## [1]  1  4  6 43
Note
vec taken from the question
vec <- c(1, 3, 2, 37)
答案5
得分: 0
另一种使用base R的方法,仅为了完整性而使用matrix:
mat <- matrix(vec, nrow=length(vec), ncol=length(vec), byrow=T)
mat[upper.tri(mat)] <- NA
apply(mat, 1, \(x) as.vector(na.omit(x)))
[[1]]
[1] 1
[[2]]
[1] 1 3
[[3]]
[1] 1 3 2
[[4]]
[1]  1  3  2 37
英文:
Another base R approach using matrix just for completeness
mat <- matrix(vec, nrow=length(vec), ncol=length(vec), byrow=T)
mat[upper.tri(mat)] <- NA
apply(mat, 1, \(x) as.vector(na.omit(x)))
[[1]]
[1] 1
[[2]]
[1] 1 3
[[3]]
[1] 1 3 2
[[4]]
[1]  1  3  2 37
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论