I have several data frames that are generated by a script, and sometimes they are empty. At the end of my procedure I would like to use cbind
to put all of the data frames together, however this of course fails if the data frame is "empty."
df1 <- structure(list(id1 = c("A", "A", "B", "B", "A", "A"),
val1 = c(4,2, 1, 5, 3, 4),
id2 = c("C", "B", "C", "C", "B", NA),
val2 = c(2, 3, 2, 2, 3, NA)),
row.names = c(NA, 6L), class = "data.frame")
df2 <- structure(list(), names = character(0),
row.names = integer(0),
class = c("tbl_df", "tbl", "data.frame"))
df3 <- structure(list(id3 = c("X", "X", "X", "Y", "Y", "Y"),
val3 = c(8, 10, 11, 9, 22, 1)),
class = "data.frame", row.names = c(NA, -6L))
I have tried to do this with a nested ifelse
statement. For example:
df_new <- ifelse(nrow(df1)==0, cbind(df2, df3),
ifelse(nrow(df2)==0, cbind(df1, df3),
cbind(df1, df2, df3)))
However, this just returns the first column of df1
as a list... Is there a better way to achieve this? Or is there something about ifelse
or cbind
that I'm not understanding? Thank you in advance!
You can put your data.frame
s in a list, remove the empty elements (length == 0
), and then use cbind
in a do.call
function.
l <- list(df1, df2, df3)
do.call("cbind", l[lengths(l) > 0])
# id1 val1 id2 val2 id3 val3
# 1 A 4 C 2 X 8
# 2 A 2 B 3 X 10
# 3 B 1 C 2 X 11
# 4 B 5 C 2 Y 9
# 5 A 3 B 3 Y 22
# 6 A 4 <NA> NA Y 1
If you prefer dplyr
functions, you can use dplyr::bind_cols
:
dplyr::bind_cols(l[lengths(l) > 0])
Also purrr
has a convenient function that you can use to remove empty elements, compact
:
dplyr::bind_cols(purrr::compact(l))