Search code examples
rpurrr

Add a layer to a list following names


I have this one layer list :

have <- list("a" = 1, "b.a" = 2, "b.b" = 3)

I need this 2 layers list :

need <- list("a" = 1, "b" = list("a" = 2, "b" = 3))

Would be even better if the solution could be recursive. The goal is to structurate the data as it could be parsed to some Json file for example.

Thank you !


Solution

  • This recursive function should do the trick:

    f <- function(obj) {
      nms <- lapply(strsplit(names(obj), '\\.'), function(x){
        if(length(x) == 1) x else c(x[1], paste(x[-1], collapse = '.'))
      })
      first_nms <- sapply(nms, `[`, 1)
      last_nms <- sapply(nms, `[`, -1)
      un_nms <- unique(first_nms)
      setNames(lapply(un_nms, function(x) {
        o <- unname(obj[first_nms %in% x])
        if(length(o) == 1) unlist(o) else
          f(setNames(o, last_nms[first_nms %in% x]))
        }), un_nms)
    }
    

    Testing, we have:

    have <- list("a" = 1, "b.a" = 2, "b.b" = 3)
    
    f(have)
    #> $a
    #> [1] 1
    #> 
    #> $b
    #> $b$a
    #> [1] 2
    #> 
    #> $b$b
    #> [1] 3
    

    And we can see it works on deeply nested lists:

    f(list(a = 1, b.a = 2, b.b = 3, c.a.a = 4, c.a.b = 5, c.b.a = 6, c.b.b = 7))
    #> $a
    #> [1] 1
    #> 
    #> $b
    #> $b$a
    #> [1] 2
    #> 
    #> $b$b
    #> [1] 3
    #> 
    #> 
    #> $c
    #> $c$a
    #> $c$a$a
    #> [1] 4
    #> 
    #> $c$a$b
    #> [1] 5
    #> 
    #> 
    #> $c$b
    #> $c$b$a
    #> [1] 6
    #> 
    #> $c$b$b
    #> [1] 7