Why Does Unlist() Kill Dates in R

Why does unlist() kill dates in R?

do.call is a handy function to "do something" with a list. In our case, concatenate it using c. It's not uncommon to cbind or rbind data.frames from a list into a single big data.frame.

What we're doing here is actually concatenating elements of the dd list. This would be analogous to c(dd[[1]], dd[[2]]). Note that c can be supplied as a function or as a character.

> dd <- list(dd, dd)
> (d <- do.call("c", dd))
[1] "2013-01-01" "2013-02-01" "2013-03-01" "2013-01-01" "2013-02-01" "2013-03-01"
> class(d) # proof that class is still Date
[1] "Date"

Why might one use the unlist() function? (example inside)

dplyr functions, such as filter() and select(), return tibbles (a variant on data.frames). Data frames and tibbles are a special type of list, where each element is a vector of the same length, but not necessarily the same type.

In the example given, each statement is selecting a single column, returned as a 1-column tibble. A 1-column tibble is a list with one element, in this case the vector of Bodyweights. However, many functions do not expect a 1-column tibble (or data.frame), but want a vector. By using unlist(), we are squashing the structure down to a single vector. This would be true whether you selected a single column or multiple columns.

The idiomatic way in dplyr would be to pipe pull(Bodyweight), as opposed to using unlist().

Consider this simple example for the difference

tib <- tibble(a = 1:5, b = letters[1:5])
select(tib, a)
class(select(tib, a))
# Notice the different printing and class when we unlist
unlist(select(tib, a))
class(unlist(select(tib, a))

unlist removes class in list elements (POSIXlt)

Usually it's far better to use POSIXct. However, if your list is not nested you could use c:

do.call(c, dates)

How to unlist result of lapply involving function(x) as.Date(as.POSIXct(x, origin = 1970-01-01 ))

Use do.call():

list <- lapply(data$displayDate, function(x) as.Date(as.POSIXct(x, origin = "1970-01-01")))
vec <- do.call("c", list)

By the way, a quick search through the SO database would have turned up this gem.

Unlist lists of lists in R

Here's a recursive approach. It applies a similar logic to what you would use as a human.

flat <- list()
finder <- function(l) {
for (element in l) {
if (inherits(element, "data.frame")) {
flat <<- c(flat, list(element))
} else {
finder(element)
}
}
return(flat)
}

Once you have run the above, you can call it with Reduce(rbind, finder(your_list))

I'm not sure how to approach it without having to use <<- so would love feedback from those more knowledgeable than myself.

Unlisting nested lists and without loosing object classes

You can use Reduce() or do.call() to be able to combine all of the to one dataframe. The code below should work

      Reduce(rbind,lapply(myList,data.frame,stringsAsFactors=F))

var1 var2 var3
1 A 1 1999-01-01
2 B 2 2000-01-01
3 C 3 2001-01-01
4 D 4 2002-01-01
5 Q 11 1999-01-02
6 W 22 2000-01-03
7 E 33 2001-01-04
8 R 44 2002-01-05

Also the class is maintained:

  mapply(class,Reduce(rbind,lapply(myList,data.frame,stringsAsFactors=F)))
var1 var2 var3
"character" "numeric" "Date"

How to keep zero-length element when using c() on a list?

For use in a data frame you'd prefer NA's over Date(0). E.g.

ex_list[sapply(ex_list, rlang::is_empty)] <- NA
ex_vector <- do.call(c, ex_list)
df <- data.frame(id = c("A", "B", "C"))
df$dates <- ex_vector

Or a tidyverse-solution:

library(tidyverse)

data.frame(id = c("A", "B", "C")) |>
add_column(as_tibble_col(ex_list, column_name = "dates")) |>
unnest(dates, keep_empty = TRUE)

unlist() gives unexpected results when used against a dataframe

You can split the string on comma (,), convert the data to numeric and use order to get the order and collapse the data in one comma-separated string.

x = c( " 11, 13, 2", " 10 ,100, 11")
df2 = data.frame(x)
df2$y <- sapply(strsplit(trimws(df2$x), "\\s*,\\s*"), function(x)
toString(order(as.numeric(x))))

df2
# x y
#1 11, 13, 2 3, 1, 2
#2 10 ,100, 11 1, 3, 2

Using sort(..., index.return = TRUE).

df2$y <- sapply(strsplit(trimws(df2$x), "\\s*,\\s*"), function(x)
toString(sort(as.numeric(x), index.return=TRUE)$ix))

Using lapply will give y as list :

df2$y <- lapply(strsplit(trimws(df2$x), "\\s*,\\s*"), function(x) 
order(as.numeric(x)))


Related Topics



Leave a reply



Submit