Looping over a Date or POSIXct object results in a numeric iterator
?"for"
says that seq
(the part after in
) is "[A]n expression evaluating to a vector (including a list and an expression) or to a pairlist or 'NULL'".
So your Date
vector is being coerced to numeric
because Date
objects aren't strictly vectors:
is.vector(Sys.Date())
# [1] FALSE
is.vector(as.numeric(Sys.Date()))
# [1] TRUE
The same is true for POSIXct
vectors:
is.vector(Sys.time())
# [1] FALSE
is.vector(as.numeric(Sys.time()))
# [1] TRUE
How to iterate over list of Dates without coercion to numeric?
There are two issues here. One is whether the input gets coerced from Date
to numeric
. The other is whether the output gets coerced to numeric
.
Input
For loops coerce Date
inputs to numeric
, because as @DWin and @JoshuaUlrich point out, for
loops take vectors
, and Date
s are technically not vectors.
> for(d in dates) print(class(d))
[1] "numeric"
[1] "numeric"
On the other hand, lapply
and its simplifier offspring sapply
have no such restrictions.
> sapply( dates, function(day) class(day) )
[1] "Date" "Date"
Output
However! The output of class()
above is a character. If you try actually returning a date object, sapply
is not what you want.
lapply
does not coerce to a vector, but sapply
does:
> lapply( dates, identity )
[[1]]
[1] "2013-01-01"
[[2]]
[1] "2013-01-02"
> sapply( dates, identity )
[1] 15706 15707
That's because sapply
's simplification function coerces output to a vector.
Summary
So: If you have a Date
object and want to return a non-Date
object, you can use lapply
or sapply
. If you have a non-Date
object, and want to return a Date
object, you can use a for
loop or lapply
. If you have a Date
object and want to return a Date
object, use lapply
.
Resources for learning more
If you want to dig deeper into vectors, you can start with John Cook's notes, continue with the R Inferno, and continue with SDA.
Print a date range in a loop with correctly formatted dates
Try:
for (i in as.list(seq(as.Date('2020-04-02'), as.Date('2020-04-30'), by = 'day'))) {
print(i)
}
I don't know why this is necessary, but if you run
for (i in Sys.Date()) {browser();print(i);}
# Called from: top level
# Browse[1]>
debug at #1: print(i)
# Browse[1]>
i
# [1] 18709
you'll see that i
is being converted to numeric in the for (.)
portion. The as.list
helps preserve that class.
Why i am getting error while I am looping dates?
Here are two ways :
- Change the date from number to date in loop.
for (i in Weekly_Close_Price$PRICE_DATE){
print(as.Date(i, origin = '1970-01-01'))
}
- Loop over the index.
for (i in seq_along(Weekly_Close_Price$PRICE_DATE)) {
print(Weekly_Close_Price$PRICE_DATE[i])
}
R for loop with in type conversion
As suggested by @flodel , the for loop preserve the Type and not the class:
h <- seq(as.Date('20090101','%Y%m%d'),as.Date('20090105','%Y%m%d'),1)
class(h)
[1] "Date"
> typeof(h)
[1] "double"
Work around :
Use the vectorize version :
print(seq(as.Date('20090101','%Y%m%d'),as.Date('20090105','%Y%m%d'),1 ))
or loop over the sequence indices and retrieve the date with [
:
for (i in seq_along(h)) {
dt <- h[i]
print(dt)
}
[1] "2009-01-01"
[1] "2009-01-02"
[1] "2009-01-03"
[1] "2009-01-04"
[1] "2009-01-05"
Converting date in For Loop in R - origin must be supplied
The for
is creating d
as numeric. Here are two approaches.
Below the comments were removed and only the code lines marked ##
have been changed.
1) list Use a list like this:
dates <- seq(as.Date("1987-03-29"), as.Date("1991-12-31"), by=1)
for (d in as.list(dates)) { ##
year <- strftime(d, "%Y")
print(year)
}
2) as.Date or convert d
back to "Date"
class.
dates <- seq(as.Date("1987-03-29"), as.Date("1991-12-31"), by=1)
for (d in dates) {
year <- strftime(as.Date(d, origin = "1970-01-01"), "%Y") ##
print(year)
}
Retrieving date from sequence does not give the value
Your date values are converted to numeric in for()
function to use them as index values.
Instead you can use seq_along()
to get index values and then print mySeq[i]
.
for(i in seq_along(mySeq)) {print(mySeq[i])}
How to avoid R converting dates to numeric automatically?
The for
loop coerces the sequence to vector, unless it is vector, list, or some other things. date
is not a vector, and there is no such thing as vector of dates. So you need as.list
to protect it from coercion to vector:
for (d in as.list(date)) print(d)
Related Topics
Select the Row With the Maximum Value in Each Group
Count Number of Rows Within Each Group
Quickly Reading Very Large Tables as Dataframes
How to Find the Statistical Mode
Use Dynamic Name For New Column/Variable in 'Dplyr'
Split Delimited Strings in a Column and Insert as New Rows
Find Complement of a Data Frame (Anti - Join)
Reshape Three Column Data Frame to Matrix ("Long" to "Wide" Format)
How to Implement Coalesce Efficiently in R
Combine Two Data Frames by Rows (Rbind) When They Have Different Sets of Columns
Select the Top N Values by Group
Generating All Distinct Permutations of a List in R
How to Plot Two Histograms Together in R
Ggplot Does Not Work If It Is Inside a For Loop Although It Works Outside of It
Splitting a Dataframe String Column into Multiple Different Columns
Increasing (Or Decreasing) the Memory Available to R Processes