代码之家  ›  专栏  ›  技术社区  ›  Jon Spring

使用lubridate::month()编写矢量化函数以生成会计年度

  •  1
  • Jon Spring  · 技术社区  · 5 年前

    例如,给定两年的日期,我希望这个数据的输出是 c(1:12, 1:12) :

    data.frame(perf_dt = seq.Date(from = as.Date("2019-07-01"),
                                  to   = as.Date("2021-06-01"),
                                  by   = "month"))
    

    我现在的功能是这个。它包括允许输出标签的逻辑。

    FY_mo <- function(date, label = F, abbrev = F) {
      a <- (5 + (lubridate::month(date) %% 12)) + 1
      CY_num = lubridate::month(date)
      ifelse(!label, a,
              ifelse(abbrev,
                      month.abb[CY_num],
                      month.name[CY_num]))
    }
    

    当我为它提供单独的日期时,这是有效的。例如,此测试来自 testthat 通行证:

    test_that("FY_mo works on indiv input dates", {
      expect_equal(7, FY_mo(as.Date("2020-01-01")))
      expect_equal("January", FY_mo(as.Date("2020-01-01"), label = TRUE))
      expect_equal("Jan", FY_mo(as.Date("2020-01-01"), label = TRUE, abbrev = TRUE))
    })
    

    但是当我给它一个向量的时候它就不起作用了。下面的代码输出全部“13”。

    data.frame(perf_dt = seq.Date(from = as.Date("2019-07-01"),
                                                 to =   as.Date("2021-06-01"),
                                                 by = "month")) %>%
                     dplyr::mutate(FY_mo = FY_mo(perf_dt)) %>%
                     dplyr::pull(FY_mo)
    #[1] 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13
    

    我的错在哪里?有没有更好的方法来构造函数以产生矢量的正确输出?

    1 回复  |  直到 5 年前
        1
  •  2
  •   Ronak Shah    5 年前

    这不是一个错误,但因为我们正在使用 ifelse 检查一下这里的情况 如果有的话 返回长度与 test . 作为我们的 测试 length(!label) )它只返回第一个值并循环使用。因为我们只有一个条件可以检查 if / else 而不是 这样可以避免这个问题。

    FY_mo <- function(date, label = F, abbrev = F) {
      a <- match(lubridate::month(date), c(7:12, 1:6))
      CY_num = lubridate::month(date)
      if(!label) a
      else if (abbrev) month.abb[CY_num]
           else month.name[CY_num]       
    }
    
    data.frame(perf_dt = seq.Date(from = as.Date("2019-07-01"),
                                  to =   as.Date("2021-06-01"),
                                  by = "month")) %>%
      dplyr::mutate(FY_mo = FY_mo(perf_dt)) %>%
      dplyr::pull(FY_mo)
    
    #[1] 1  2  3  4  5  6  7  8  9 10 11 12  1  2  3  4  5  6  7  8  9 10 11 12