generate sequence of consecutive and overlapping numeric blocks
Asked Answered
D

5

5

From this

x <- 1:10
block.size <- 3L

I would like to generate a sequence of consecutive and overlapping blocks of length 3 like so:

1,2,3
2,3,4
3,4,5
4,5,6
5,6,7
6,7,8
7,8,9
8,9,10

I found this nice answer which works with characters.

I can think of a loop to do this, but I would definitely prefer a more concise and vectorized way if possible. Here is my take.

block.nums <- length(x)-len+1
blocks <- vector(mode = "list", length = block.nums)

for (i in 1:block.nums) {
  blocks[[i]] <- i:(i+block.size-1)
}
Diez answered 22/9, 2023 at 12:56 Comment(1)
is it important to you that the numbers are in increasing order? I see in your example they are, but in your description you don't mention thisSulphur
E
7

Try embed()

> embed(x, block.size)[, block.size:1]
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    2    3    4
[3,]    3    4    5
[4,]    4    5    6
[5,]    5    6    7
[6,]    6    7    8
[7,]    7    8    9
[8,]    8    9   10

Or, sequence

matrix(
    sequence(
        rep(1 + length(x) - block.size, block.size),
        from = head(seq_along(x), block.size)
    ),
    ncol = block.size
)

which gives the desired output as well

     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    2    3    4
[3,]    3    4    5
[4,]    4    5    6
[5,]    5    6    7
[6,]    6    7    8
[7,]    7    8    9
[8,]    8    9   10
Elaineelam answered 22/9, 2023 at 13:20 Comment(3)
I just tested this with x <- 1:10000 block.size <- 100, and the sequence version you wrote is about 115 times faster than the slowest answer. Bravo!Sulphur
@Sulphur aha, that's an interesting observation, I didn't know that before :PElaineelam
So many great answers! I decided to accept this one (the embed one) since it seems to me the most concise and straight way to do it (personal preference). Thanks to you (and all other users that provided their answers, +1 to everybody :)Diez
J
5

You could try:

ll <- length(x) - (block.size - 1) # number of rows
mat <- matrix(NA, nrow = length(x) - (block.size - 1), ncol = block.size) # initiate a blank matrix

sapply(seq_len(block.size), \(xx) mat[,xx] <- x[seq_len(ll) - 1 + xx])

Output:

     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    2    3    4
[3,]    3    4    5
[4,]    4    5    6
[5,]    5    6    7
[6,]    6    7    8
[7,]    7    8    9
[8,]    8    9   10
James answered 22/9, 2023 at 13:9 Comment(0)
P
4

Here a function

> f <- \(n, s) {
+   stopifnot(s > 0 && s <= n)
+   if (s == 1) as.matrix(seq_len(n))
+   else t(sapply(1:(n - s + 1L), `+`, 0:(s - 1L)))
+ }
> f(10, 3)
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    2    3    4
[3,]    3    4    5
[4,]    4    5    6
[5,]    5    6    7
[6,]    6    7    8
[7,]    7    8    9
[8,]    8    9   10
> f(5, 2)
     [,1] [,2]
[1,]    1    2
[2,]    2    3
[3,]    3    4
[4,]    4    5
> f(5, 1)
     [,1]
[1,]    1
[2,]    2
[3,]    3
[4,]    4
[5,]    5
> f(1, 1)
     [,1]
[1,]    1
> f(5, 6)
Error in f(5, 6) : s > 0 && s <= n is not TRUE
Plash answered 22/9, 2023 at 13:23 Comment(0)
O
4

A possibility would be to use outer.

outer(1:8, 0:2, `+`)
#outer(seq_len(length(x)-block.size+1), 0:(block.size-1), `+`) # Alternative with given data
#     [,1] [,2] [,3]
#[1,]    1    2    3
#[2,]    2    3    4
#[3,]    3    4    5
#[4,]    4    5    6
#[5,]    5    6    7
#[6,]    6    7    8
#[7,]    7    8    9
#[8,]    8    9   10

Or matrix with auto repeat and vector addition.

matrix(0:2, 8, 3, TRUE) + 1:8
#     [,1] [,2] [,3]
#[1,]    1    2    3
#[2,]    2    3    4
#[3,]    3    4    5
#[4,]    4    5    6
#[5,]    5    6    7
#[6,]    6    7    8
#[7,]    7    8    9
#[8,]    8    9   10
Ophir answered 28/9, 2023 at 20:37 Comment(0)
S
3

Here's another way (most likely slower than the others):

vapply(head(x, -block.size), \(s) seq(s, s + block.size - 1), integer(block.size)) |> t()

# Output is the same as the other ones ;)

Notes:

  1. vapply() is similar to the other *apply() functions, but requires you to add an output type and size. The documentation says it is sometimes faster (though doesn't specify in which situations, frustratingly!)
  2. head() in this case is getting everything except the last block.size elements of x
Sulphur answered 22/9, 2023 at 13:21 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.