Search code examples
rvectorsequenceseq

How to make a sequence like 1:n, 1:(n-1), ... 1:2, 1?


n is an integer. The sequence I would like is:

1:n, 1:(n-1), 1:(n-2), ... , 1:3, 1:2, 1

Editor note:

In R, 1:n-1 is different from 1:(n-1). Be careful.


Solution

  • As short as sequence(n:1).

    sequence(4:1)
    #[1] 1 2 3 4 1 2 3 1 2 1
    

    The function does no mystery (see note at the bottom):

    function (nvec) 
    unlist(lapply(nvec, seq_len))
    

    So snoram's answer reinvents the wheel. But calling seq_len is faster than calling other options as it is a primitive function (a C function) with only one argument.

    sequence2 <- function (nvec) unlist(lapply(nvec, seq.int, from = 1))
    sequence3 <- function (nvec) unlist(lapply(nvec, function(x) 1:x))
    sequence4 <- function (nvec) unlist(lapply(nvec, seq.default, from = 1))
    sequence5 <- function (nvec) unlist(lapply(nvec, seq, from = 1))
    
    library(microbenchmark)
    microbenchmark(sequence(100:1), sequence2(100:1),
                   sequence3(100:1), sequence4(100:1), sequence5(100:1))
    #Unit: microseconds
    #             expr     min        lq      mean    median        uq      max
    #  sequence(100:1)  93.292  160.9325  205.5617  173.1995  200.0005 1157.201
    # sequence2(100:1) 117.625  226.2120  308.4929  248.1055  280.8625 5477.710
    # sequence3(100:1) 126.289  233.7875  365.6455  268.0495  301.8860 8808.911
    # sequence4(100:1) 606.301 1195.4795 1463.3400 1237.5580 1344.3145 9986.619
    # sequence5(100:1) 944.099 1864.3920 2063.3712 1942.2240 2119.3930 8581.593
    
    ## speed comparison
        seq     <  seq.default  <  function(x) 1:x  <  seq.int  <       seq_len
    s3 generic       normal      light-weighted user  primitive   1-argument primitive
    

    A note on 2022-07-31

    Function sequence is now more powerful and more efficient. It no longer has source code as I showed above. I don't know when it was upgraded, though. I can't find relevant description in R NEWS.