创建循环的数字序列

create sequence of numbers which are cyclic

我有一个月份向量

m_vec <- c(3, 7, 11)

这些月份代表一个季节的开始月份。每个季节的所有月份如下所示:

season1 <- c(3,4,5,6)
season2 <- c(7,8,9,10)
season3 <- c(11,12,1,2)

我想创建一个小函数,它接受开始月份和 生成每个季节的月份向量。下面显示了更多示例:

m_vec <- c(9,12,4,8)
season1 <- c(9,10,11)
season2 <- c(12,1,2,3)
season3 <- c(4,5,6,7,8)

m_vec <- c(12, 5, 9)
season1 <- c(12, 1, 2,3,4)
season2 <- c(5,6,7,8)
season3 <- c(9,10,11)

我的 for 循环不完整,我什至不知道从哪里开始使用逻辑

n_season <- length(m_vec)
temp_list <- list()
for(m in seq_along(m_vec)){
      
   month_start <- m_vec[m]
   month_start_next <- m_vec[m + 1]
    
   month_start:month_start_next
}      

首先我们可以创建一些辅助函数

cycle <- function(n) { function(x) (x-1) %% n + 1 }
split_at <- function(b) { function(x) split(x, cumsum(x %in% b)) }

cycle() 助手将 return 一个函数,它将值保持在从 1 到您传入的 n 范围内。它使用模数 % 操作员。 split_at 助手将 return 一个函数,该函数接受一个向量并在找到您传入的值时将其拆分。它通过使用 cumsum() 计算找到每个断点的时间来做到这一点。

然后我们可以接受您的输入,从您的第一个开始月份创建一个 12 个月的向量,将其包装在循环仪中以使其保持在 1-12 之间,然后我们可以使用您的季节断点将其拆分。这是它的样子:

month_cycle <- cycle(12)
season_splitter <- split_at(m_vec)

m_vec <- c(12, 5, 9)

seq(m_vec[1], length.out=12) |>
  month_cycle() |>
  season_splitter()
# $`1`
# [1] 12  1  2  3  4
# $`2`
# [1] 5 6 7 8
# $`3`
# [1]  9 10 11

一个选项是转换为 Date class,获取 sequence 并提取 months

library(lubridate)
fn1 <- function(mvec) {
    new <- pmax(mvec-1, 1)
    out <- Map(function(i, j) {
       date1 <- mdy(i, truncated = 2)
       date2 <- mdy(j, truncated = 2)
      if(date1 > date2)  {
        date2 <- date2 + years(1)}
       month(seq(date1, date2, by = "month"))
       }, mvec, c(new[-1], new[1]))
    if(length(out[[length(out)]]) < 2) {
           out[[length(out)-1]] <- c(out[[length(out)-1]], out[[length(out)]])
           out[[length(out)]] <- NULL
   }
    names(out) <- paste0("season", seq_along(out))
    return(out)
  }

-测试

> fn1(m_vec)
$season1
[1] 3 4 5 6

$season2
[1]  7  8  9 10

$season3
[1] 11 12  1  2

> fn1(c(9, 12, 4, 8))
$season1
[1]  9 10 11

$season2
[1] 12  1  2  3

$season3
[1] 4 5 6 7 8
> fn1(c(1, 5, 11))
$season1
[1] 1 2 3 4

$season2
[1]  5  6  7  8  9 10

$season3
[1] 11 12  1
m_vec <- c(12, 5, 9)
Map(function(x, y) head((((x:(x + ((y - x) %% 12))) - 1) %% 12) + 1, -1),
    m_vec,
    c(m_vec[-1], m_vec[1]))
#[[1]]
#[1] 12  1  2  3  4

#[[2]]
#[1] 5 6 7 8

#[[3]]
#[1]  9 10 11