Home > Software design >  purrr::flatten a list but maintain the hierarchy name
purrr::flatten a list but maintain the hierarchy name

Time:09-17

Suppose I have a list of named vectors:

test_list <- list("grp1" = c(subgrp1 = "A", subgrp2 = "B"),
                  "grp2" = c(subgrp1 = "A", subgrp2 = "B"), 
                  "grp3" = c(subgrp1 = "A"))

I want to change this into

want_list <- list("grp1 - subgrp1" = c(subgrp1 = "A"),
                  "grp1 - subgrp2" = c(subgrp2 = "B"),
                  "grp2 - subgrp1" = c(subgrp1 = "A"),
                  "grp2 - subgrp2" = c(subgrp2 = "B"),
                  "grp3" = c(subgrp1 = "A"))

purrr::flatten(test_list) returns list of length 5, but loses the "grp" hierarchy completely - which isn't surprising since that's the point of this function. I wish to "maintain" the hierarchy by keeping the name on those with length of >1.

I suppose you can rename each elements in named vector based on the layer above... but I am not sure how to do this operation in scalable manner when the list has varying length.

How can I approach this problem?

CodePudding user response:

We may need some modification by changing the names

want_list2 <- do.call(c, unname(Map(function(x, y) {
   lst1 <- lapply(seq_along(x), function(i) x[i])
   if(length(lst1) > 1)
    setNames(lst1, paste0(y, ' - ', names(x))) else setNames(lst1, y)
  }, test_list, names(test_list))))

-checking with expected output

> all.equal(want_list, want_list2)
[1] TRUE

Or using flatten and tidyverse options

library(dplyr)
library(purrr)
library(stringr)
want_list3 <- imap(test_list, ~
      map(as.list(seq_along(.x)), function(i) .x[i]) %>% 
       set_names(if(length(.x) > 1) str_c(.y, ' - ', names(.x)) else
             .y)) %>%
       flatten

-testing

> all.equal(want_list, want_list3)
[1] TRUE
  • Related