r - 用于启用类型分派(dispatch)的惯用语

标签 r class date date-range dispatch

这里有几个问题,如果其中任何一个问题得到足够好的回答,我会很满意。

背景 - 最终目标是什么?

我对在 R 中表示日期范围感兴趣。最低要求是我们表示开始日期和结束日期,这可以使用长度为 2 的日期向量轻松完成。此外,最好将此对象扩展为一个类,进一步实现

  • 为每个范围提供名称(即字符串)
  • 启用dplyr::Between 运算符(轻松)使用

我以前的方法的缺点

我之前已将每个范围表示为长度为 2 的日期向量。这里的好处是我不依赖任何外部依赖项,而且我的数据结构非常轻量级,因此编程并不麻烦。缺点是我厌倦了必须通过 [ 运算符和参数 访问日期范围的 begend分别是 12(可以说比我们有一个类实现更难解释)。

此外,我们最终处理一系列日期范围(即向量),因此在开始嵌套数据结构之前抽象出 DateRange 很有帮助。我不想使用长度为 2 的日期向量列表,也不想使用包含两行的 data.frame,每列都被解释为一个日期范围。

我看过哪里?

我查看了 lubridate 包并考虑了从 Interval 类继承。从这种继承开始的缺点是我认为 S4 对于我的用例来说不是必需的。我只需要一些简单的数据属性和一个很好的 API 来调用 dplyr::Between

理想的解决方案可能只是扩展 lubridate::Interval 类来保存名称、结束日期(可能是一种方法,因为此信息已通过 @start + @ 存储在 Interval 中) .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) 需要三个参数。为了尝试完成此任务,我尝试按如下方式设置类型分派(dispatch):

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 的原型(prototype)中使用 ... 的原因是,当前 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 是一个不能立即进行类型分派(dispatch)的函数,因此我自己实现它会产生代码味道。

最佳答案

一种可能是使用data.tableinrange函数。

首先,让我们做一个间隔:

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 的中缀变体:

`%my.inrange%` <- my.inrange

现在您也可以在以下表示法中使用它:

"2012-02-01" %my.inrange% mi

这类似于 data.table Betweeninrange 函数的中缀表示法。

关于r - 用于启用类型分派(dispatch)的惯用语,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47444624/

相关文章:

mysql - 按时间间隔选择记录 12 :00:00 and 18:00:00 on every day

r - 将某些列的名称作为数据框每一行的一个单元格

r - Pmetrics : declare default fortran compiler before calling PMBuild()

jQuery:如何使用特殊类来寻址子项

java:用==或.equals()比较类:有区别吗?

MySQl DATE Format 将 Varchar 更新为不同格式的日期

android检查应用程序是否连续多天打开

r - 如何避免在任何时间(<numeric>) "updates by reference"?

r - dplyr:子集、总结和变异新函数的工作流程

java - Java多个文件和文件夹层次结构