Implementation of standard recycling rules
Solution 1:
I've used this in the past,
expand_args <- function(...){
dots <- list(...)
max_length <- max(sapply(dots, length))
lapply(dots, rep, length.out = max_length)
}
Solution 2:
I'd likely use the length.out
argument of rep()
to do most of the real work.
Here's an example that creates a better.data.frame()
function (it should really be called "better".data.frame()
), which places no restrictions on the lengths of the vectors it's handed as arguments. In this case, I recycle all of the vectors to the length of the the longest one, but you can obviously adapt this to serve your own recycling needs!
better.data.frame <- function(...) {
cols <- list(...)
names(cols) <- sapply(as.list(match.call()), deparse)[-1]
# Find the length of the longest vector
# and then recycle all columns to that length.
n <- max(lengths(cols))
cols <- lapply(cols, rep, length.out = n)
as.data.frame(cols)
}
# Try it out
a <- Sys.Date() + 0:9
b <- 1:3
c <- letters[1:4]
data.frame(a,b,c)
# Error in data.frame(a, b, c) :
# arguments imply differing number of rows: 10, 3, 4
better.data.frame(a,b,c)
# a b c
# 1 2012-02-17 1 a
# 2 2012-02-18 2 b
# 3 2012-02-19 3 c
# 4 2012-02-20 1 d
# 5 2012-02-21 2 a
# 6 2012-02-22 3 b
# 7 2012-02-23 1 c
# 8 2012-02-24 2 d
# 9 2012-02-25 3 a
# 10 2012-02-26 1 b
Solution 3:
One short-and-dirty route for numerical arguments is to rely on cbind's automatic recycling. For example:
f.abc <- function(a,b,c) {
df.abc <- as.data.frame( suppressWarnings( cbind(a=a, b=b, c=c) ) )
#Then use, for example, with() to use a, b and c inside the data frame,
#or apply(df.abc,1, ...)
}
It does rely heavily on there being no other legitimate cause for warnings, though.