Get a seq() in R with alternating steps

2019-01-27 21:33发布

问题:

The seq function in R would give me a sequence from x to y with a constant step m:

seq(x, y, m)

E.g. seq(1,9,2) = c(1,3,5,7,9).

What would be the most elegant way to get a sequence from x to y with alternating steps m1 and m2, such that something like "seq(x, y, c(m1, m2))" would give me c(x, x + m1, (x + m1) + m2, (x + m1 + m2) + m1, ..., y), each time adding one of the steps (not necessarily reaching up to y, of course, as in seq)?

Example: x = 1; y = 19; m1 = 2; m2 = 4 and I get c(1,3,7,9,13,15,19).

回答1:

I arrived the solution by: 1. Use cumsum with a vector c(from,rep(by,times),...), with by repeated times = ceiling((to-from)/sum(by)) times. 2. Truncate the sequence by !(seq > to).

 seq_alt <- function(from, to, by) {
   seq <- cumsum(c(from,rep(by,ceiling((to-from)/sum(by)))))
   return(seq[! seq > to])
 }


回答2:

First n terms of this sequence you can generate with

x = 1; m1 = 2; m2 = 4

n <- 0:10 # first 11 terms
x + ceiling(n/2)*m1 + ceiling((n-1)/2)*m2
# [1] 1  3  7  9 13 15 19 21 25 27 31


回答3:

Here is another idea,

fun1 <- function(x, y, j, z){
if(j >= y) {return(x)}else{
  s1 <- seq(x, y, j+z)
  s2 <- seq(x+j, y, j+z)
  return(sort(c(s1, s2)))
  }
}

fun1(1, 19, 2, 4)
#[1]  1  3  7  9 13 15 19

fun1(1, 40, 4, 3)
#[1]  1  5  8 12 15 19 22 26 29 33 36 40

fun1(3, 56, 7, 10)
#[1]  3 10 20 27 37 44 54

fun1(1, 2, 2, 4)
#[1] 1


回答4:

Here is an alternative that uses diffinv This method over allocates the values, so as a stopping rule, I get the elements that are less than or equal to the stopping value.

seqAlt <- function(start, stop, by1, by2) {
   out <- diffinv(rep(c(by1, by2), ceiling(stop / (by1 + by2))), xi=start)
   return(out[out <= stop])
}

seqAlt(1, 19, 2, 4)
[1]  1  3  7  9 13 15 19


回答5:

You could use Reduce with accumulate = TRUE to iteratively add either 2 or 4:

Reduce(`+`, rep(c(2,4), 10), init = 1, accumulate = TRUE)
# [1]  1  3  7  9 13 15 19 21 25 27 31 33 37 39 43 45 49 51 55 57 61

The number of times you repeat c(2,4) will determine sequence length; since it is 10 above, the sequence is length 20.

The purrr package has an accumulate wrapper, if you prefer the syntax:

purrr::accumulate(rep(c(2,4), 10), `+`, .init = 1)
## [1]  1  3  7  9 13 15 19 21 25 27 31 33 37 39 43 45 49 51 55 57 61


回答6:

perfect example of recycling vectors in R

# 1. 
x = 1; y = 19; m1 = 2; m2 = 4
(x:y)[c(TRUE, rep(FALSE, m1-1), TRUE, rep(FALSE,m2-1))]
# [1]  1  3  7  9 13 15 19
# 2.
x = 3; y = 56; m1 = 7; m2 = 10
(x:y)[c(TRUE, rep(FALSE, m1-1), TRUE, rep(FALSE,m2-1))]
# [1]  3 10 20 27 37 44 54


标签: r seq