Sequence expansion question
Asked Answered
C

3

7

I have a sequence of 'endpoints', e.g.:

c(7,10,5,11,15)     

that I want to expand to a sequence of 'elapsed time' between the endpoints, e.g.

c(7,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,1,2,3,4,5,6,7,8,9,10,11,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)

Whats the most efficient way to do this in R? I'm imagining some creative use of the embed function, but I can't quite get there without using a ugly for loop.

Here's the naive way to do this:

expandSequence <- function(x) {
    out <- x[1]
    for (y in (x[-1])) {
        out <- c(out,seq(1,y))
    }
    return(out)
}

expandSequence(c(7,10,5,11,15))
Corpse answered 3/8, 2011 at 22:24 Comment(1)
Thanks for a nicely worded and reproducible question.Steam
L
8

There is a base function to do this, called, wait for it, sequence:

sequence(c(7,10,5,11,15))

 [1]  1  2  3  4  5  6  7  1  2  3  4  5  6  7  8  9 10  1  2  3  4  5  1  2  3
[26]  4  5  6  7  8  9 10 11  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15

In your case it seems your first endpoint is in fact not part of the sequence, so it becomes:

c(7, sequence(c(10,5,11,15)))
 [1]  7  1  2  3  4  5  6  7  8  9 10  1  2  3  4  5  1  2  3  4  5  6  7  8  9
[26] 10 11  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
Leatrice answered 3/8, 2011 at 22:38 Comment(2)
+1 Nice catch. It is implemented effectively as @gsk and I reinvented. I'd come across sequence before but presumed it was an alias for seq. Great to find out about these less well-used functions!April
@Andrie: Thanks! For my next trick, I will reverse engineer the embed function.Corpse
S
4

How about this:

> unlist(sapply(x,seq))
 [1]  1  2  3  4  5  6  7  1  2  3  4  5  6  7  8  9 10  1  2  3  4  5  1  2
[25]  3  4  5  6  7  8  9 10 11  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15

With the first element added on at the end:

c( x[1], unlist( sapply( x[seq(2,length(x))], seq ) ) )

And a slightly more readable version:

library(taRifx)
c( x[1], unlist( sapply( shift(x,wrap=FALSE), seq ) ) )
Steam answered 3/8, 2011 at 22:29 Comment(6)
Sadly my solution doesn't involve bolded numbers. ;-)Steam
Perfect! I just got to do.call(c,mapply(seq,1,x)) but your solution is better.Corpse
Except that isn't the output shown in the Q. The first element should be 7 according to the Q. You have 1:7.April
So to be complete about this you'd need to omit the first element of x from the sapply call and then add it back on to the front afterwards, to get the OP's desired output, right?Devoir
If that is what the OP wants. He has commented here that the output is "perfect", so perhaps the Q is not exactly what was wanted?April
@Gavin Simpson I added the "omit first element of x and add it back at the end" myselfCorpse
A
3

A combination of lapply() and seq_len() is useful here:

expandSequence <- function(x) {
    out <- lapply(x[-1], seq_len)
    do.call(c, c(x[1], out))
}

Which gives for

pts <- c(7,10,5,11,15)

> expandSequence(pts)
 [1]  7  1  2  3  4  5  6  7  8  9 10  1  2  3  4  5  1  2  3  4
[21]  5  6  7  8  9 10 11  1  2  3  4  5  6  7  8  9 10 11 12 13
[41] 14 15

(An alternative is:

expandSequence <- function(x) {
    out <- lapply(x[-1], seq_len)
    unlist(c(x[1], out), use.names = FALSE)
}

)

April answered 3/8, 2011 at 22:34 Comment(1)
I like reinventing the wheel!April

© 2022 - 2024 — McMap. All rights reserved.