R (purrr) flatten list of named lists to list and keep names

妖精的绣舞 提交于 2020-12-26 07:39:27

问题


Maybe I'm missing something obvious but trying to flatten a list of named lists of named lists in R (may even be more nested) into eventually one flat list. purrr and rlist seem to have tools for that. How can I achieve that names of sublists become name precrypts of flattened result list, e.g. list1.blist.a in purrr? My actual list is more deeply nested with varying number of levels and repeating names on different levels. In the end I perform purrr::map_df(final_list, bind_rows) and this seems to drop all duplicate names (and even if it didn't I don't know from which branch the original duplicate name comes from). I can do it with rlist but I had hoped for a tidyverse solution (nothing against fantastic rlist but many already have tidyverse installed).

EDIT:

Also note that rlist::list.flatten() will always remove all levels but the top while purrr::flatten() drops levels one at a time which may sometimes be what you need. You could achieve the same by nesting purrr::map(.x, .f = rlist::list.flatten) as often as you require but it's cumbersome and not beautiful/readable.

alist <- list(list1 = list(a = 1, b = 2, blist = list(a = 3, b = 4)),
              list2 = list(a = 1, b = 2, blist = list(a = 3, b = 4)))
str(alist)

List of 2
 $ list1:List of 3
  ..$ a    : num 1
  ..$ b    : num 2
  ..$ blist:List of 2
  .. ..$ a: num 3
  .. ..$ b: num 4
 $ list2:List of 3
  ..$ a    : num 1
  ..$ b    : num 2
  ..$ blist:List of 2
  .. ..$ a: num 3
  .. ..$ b: num 4

alist_flat <- purrr::map(alist, purrr::flatten)
str(alist_flat)

List of 2
 $ list1:List of 4
  ..$ a: num 1
  ..$ b: num 2
  ..$ a: num 3
  ..$ b: num 4
 $ list2:List of 4
  ..$ a: num 1
  ..$ b: num 2
  ..$ a: num 3
  ..$ b: num 4

alist_flattest <- purrr::flatten(alist_flat)
str(alist_flattest)

List of 8
 $ a: num 1
 $ b: num 2
 $ a: num 3
 $ b: num 4
 $ a: num 1
 $ b: num 2
 $ a: num 3
 $ b: num 4

# works with rlist
alist_flat_names <- map(alist, rlist::list.flatten, use.names = TRUE)
str(alist_flat_names)

List of 2
 $ list1:List of 4
  ..$ a      : num 1
  ..$ b      : num 2
  ..$ blist.a: num 3
  ..$ blist.b: num 4
 $ list2:List of 4
  ..$ a      : num 1
  ..$ b      : num 2
  ..$ blist.a: num 3
  ..$ blist.b: num 4

alist_flattest_names <- rlist::list.flatten(alist_flat_names, use.names = TRUE)
str(alist_flattest_names)

List of 8
 $ list1.a      : num 1
 $ list1.b      : num 2
 $ list1.blist.a: num 3
 $ list1.blist.b: num 4
 $ list2.a      : num 1
 $ list2.b      : num 2
 $ list2.blist.a: num 3
 $ list2.blist.b: num 4

回答1:


I looked at the source for rlist::list.flatten() and copied the source into a new function to avoid that dependency.

my_flatten <- function (x, use.names = TRUE, classes = "ANY") 
{
  #' Source taken from rlist::list.flatten
  len <- sum(rapply(x, function(x) 1L, classes = classes))
  y <- vector("list", len)
  i <- 0L
  items <- rapply(x, function(x) {
    i <<- i + 1L
    y[[i]] <<- x
    TRUE
  }, classes = classes)
  if (use.names && !is.null(nm <- names(items))) 
    names(y) <- nm
  y
}

alist <- list(list1 = list(a = 1, b = 2, blist = list(a = 3, b = 4)),
              list2 = list(a = 1, b = 2, blist = list(a = 3, b = 4)))


flat_list <- my_flatten(alist)

str(flat_list)

Result:

List of 8
 $ list1.a      : num 1
 $ list1.b      : num 2
 $ list1.blist.a: num 3
 $ list1.blist.b: num 4
 $ list2.a      : num 1
 $ list2.b      : num 2
 $ list2.blist.a: num 3
 $ list2.blist.b: num 4


来源:https://stackoverflow.com/questions/49252400/r-purrr-flatten-list-of-named-lists-to-list-and-keep-names

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!