在 R 中遍历 lubridate 对象的向量时发生意外类型转换

问题描述 投票:0回答:1

我的问题与 this (closed) lubridate issue 有关,但更普遍地与 R 中的 for 循环有关:

library(lubridate)
dates=c(ymd("20180501"), ymd("20180502"), ymd("20180503"))
print(dates)
# [1] "2018-05-01" "2018-05-02" "2018-05-03"
# ... as expected

print(dates[1])
# [1] "2018-05-01"
# ... as expected

for(d in dates) print(d)
# [1] 17652
# [1] 17653
# [1] 17654
# ... unexpected!

当遍历

dates
时,R默默地将
dates
的元素转换为数字,因此失去了所有的日期性。这是出乎意料的,会导致错误,例如当打印日期并期待“2018-05-01”时,却得到一个整数。

github issue中lubridate dev的回复是

in

 中的 
for (x in dates)
运算符是“原始的”,不会将日期时间向量分解为日期时间。所以 x 是令人惊讶的“数字”。

他们建议改用

purrr::map
for (i in seq_along(dates))
。当然在上面的例子中
map(dates, print)
更简洁并且可能更可取,但有些情况下有人可能更喜欢使用 for 循环来迭代日期向量。

我想知道应该在哪里以及如何捕获与此行为相关的错误:

  1. 作为用户,我怎样才能最好地捕捉到 for 循环中从日期到数字的意外转换?我应该养成总是使用
    for (i in seq_along(dates)) d = dates[i] ...
    的习惯吗?
  2. 一般来说,我什么时候需要小心
    for ... in
    默默地转换我的数据?
  3. lubridate 开发人员是否可以更优雅地处理这种情况,即发出警告?
  4. 这很牵强,但是:R 开发人员可以通过修复
    in
    运算符来解决这里的问题吗?
r date for-loop type-conversion lubridate
1个回答
0
投票

我不建议您这样做,但您可以更改 for 循环来解决这个问题(至少在您自己的代码中)。

就像 R 中的几乎所有其他操作一样,

for
循环被实现为一个函数。在这种情况下,
for
是保留字,因此您需要使用反引号来引用它,但您可以定义自己的函数来替换标准函数。

例如:

myfor <- function(var, seq, expr ) {
  var <- deparse(substitute(var))
  `for` <- base::`for`
  for (i in seq_along(seq)) {
    assign(var, seq[i], envir = parent.frame())
    eval(substitute(expr), envir = parent.frame())
  }
  `for` <- myfor
  invisible(NULL)
}

`for` <- myfor

library(lubridate)
#> 
#> Attaching package: 'lubridate'
#> The following objects are masked from 'package:base':
#> 
#>     date, intersect, setdiff, union
dates=c(ymd("20180501"), ymd("20180502"), ymd("20180503"))

for(d in dates) print(d)
#> [1] "2018-05-01"
#> [1] "2018-05-02"
#> [1] "2018-05-03"

创建于 2023-02-24 与 reprex v2.0.2

我不保证我得到了这里的环境,所以使用风险自负!

关于你的问题:我想其他人已经回答了Q1 - Q3。关于 Q4:是的,他们当然可以,但我敢肯定他们不会,因为这个函数比标准的 for 循环慢得多。

© www.soinside.com 2019 - 2024. All rights reserved.