rposixct

Why does looping over a vector of POSIXct-times change the type in R?


I am using R on a regular basis and I have stumbled above something weird:

Sys.time() |> class()
times <- Sys.time()+1:3
print(times)
for (tme in times) {
  print(tme)
}
tme %in% times

This gives the output:

> Sys.time() |> class()
[1] "POSIXct" "POSIXt" 
> times <- Sys.time()+1:3
> print(times)
[1] "2024-01-18 10:00:28 CET" "2024-01-18 10:00:29 CET" "2024-01-18 10:00:30 CET"
> for (tme in times) {
+   print(tme)
+ }
[1] 1705568429
[1] 1705568430
[1] 1705568431
> tme %in% times
[1] FALSE

How is such a behaviour justifiable? I find the last line especially hard to justify (tme %in% times == FALSE).


Solution

  • Reason behind

    In for loop, the expression times will be coerced to a vector (when you see the help document by typing ?`for`

    An expression evaluating to a vector (including a list and an expression) or to a pairlist or NULL. A factor value will be coerced to a character vector. This can be a long vector.

    However, in vector, no attribute will be retained (when typing ?vector and see the description)

    vector produces a ‘simple’ vector of the given length and mode, where a ‘simple’ vector has no attribute, i.e., fulfills is.null(attributes(.)).

    Workaround

    To keep all the attributes, you can convert the values in times into a list, for example, you can use as.list(times) in for loop like below

    > for (time in as.list(times)) {
    +     print(time)
    + }
    [1] "2024-01-18 10:13:39 CET"
    [1] "2024-01-18 10:13:40 CET"
    [1] "2024-01-18 10:13:41 CET"
    

    or you can use sapply like below

    > invisible(sapply(times, print))
    [1] "2024-01-18 10:13:39 CET"
    [1] "2024-01-18 10:13:40 CET"
    [1] "2024-01-18 10:13:41 CET"