这里有几个问题,如果其中任何一个人得到足够的回答,我会感到满意。
背景 - 最终目标是什么?
我有兴趣代表R中的日期范围R。裸露的要求是我们代表一个开始日期和结束日期,可以使用长度为两个日期向量来轻松完成。此外,将此对象扩展到进一步的类
的类是很不错的- 为每个范围提供一个名称(即字符串)
- 启用(轻松)使用
dplyr::between
操作员
我以前的方法的缺点
我以前已将每个范围表示为长度为两个日期向量。这里的好处是,我不依赖任何外部依赖关系,而且我的数据结构非常轻巧,以至于与此相关的问题并不是一个麻烦。不利的一面是,我厌倦了分别通过[
操作员分别访问日期范围的beg
和end
,并且参数1
和2
(可以说比我们拥有类实施的情况少)。
此外,我们最终处理了一系列日期范围(即向量),因此在开始嵌套数据结构之前,将DateRange
抽象抽出很有帮助。我不想使用长度二的列表,也不想使用一个数据。
我看过哪里?
我已经查看了lubridate
软件包,并考虑过从Interval
类继承。从这种继承开始的缺点是,我认为S4对于我的用例不是必需的。我只需要一些简单的数据属性和一个不错的API来调用dplyr::between
。
理想的解决方案可能只会扩展lubridate::Interval
类以保持名称,结束日期(可能是一种方法,因为该信息已经通过@start + @.Data
在间隔中存储),然后扩展dplyr::between
与上述类播放。
我尝试了什么?
这是我要寻找的内容的粗略实现:
# 3 key attributes: beg, end, and name.
MyInterval <- function(beg, end, name = NULL) {
if (class(beg) == "character") beg <- as.Date(beg)
if (class(end) == "character") end <- as.Date(end)
if (is.null(name)) name <- as.character(beg)
structure(.Data = list('beg' = beg, 'end' = end, 'name' = name), class = "MyInterval")
}
现在,我希望能够超载between
操作员,以便我称其为以下内容:between(x, MyInterval)
,我们注意到dplyr::between(x, lo, hi)
期望三个参数。为了实现这一目标,我尝试设置类型进行分配,如下所示:
between <- function(...) UseMethod('between')
between.MyInterval <- function(interval, x) {
if (class(x) == "character") x <- as.Date(x)
dplyr::between(x, interval$beg, interval$end)
}
between.default <- function(x, lo, hi) dplyr::between(x, lo, hi)
我之所以选择在between
的原型中使用...
的原因是,参数的顺序当前在between.MyInterval
和between.default
之间有所不同。有更好的方法来编码吗?我相信这种行为是需要的(乍一看)
i <- MyInterval("2012-01-01", "2012-12-31")
between(i, "2012-02-01") # Dispatches to between.MyInterval. Returns True as expected.
between(150, 100, 200) # Dispatches to dplyr::between. Good, we didn't break anything?
谢谢
任何批评都受到欢迎。我知道between
是一个不从开箱即用的函数,因此我自己实现了代码的气味。
一种可能性是使用data.table
的inrange
-功能。
首先,让我们进行一个间隔:
my.interval <- function(beg, end) data.table(beg = as.Date(beg), end = as.Date(end))
mi <- my.interval("2012-01-01", "2012-12-31")
现在您可以做:
> as.Date("2012-02-01") %inrange% mi
[1] TRUE
或定义您自己的inrange
-函数:
my.inrange <- function(x, intv) data.table::inrange(as.Date(x), intv$beg, intv$end)
您可以做:
> my.inrange("2012-02-01", mi)
[1] TRUE
正如@frank所说的那样,您也可以制作my.inrange
的infix变体:
`%my.inrange%` <- my.inrange
现在您也可以在以下表示法中使用它:
"2012-02-01" %my.inrange% mi
类似于data.table
'S between
和inrange
函数的infix符号。