Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
827 views
in Technique[技术] by (71.8m points)

r - Nested list based on flat/condensed name structure of named vector or list

I'm looking for a simple way to create a nested list based on a "flat" or condensed name structure of either a named vector or a list

E.g., input c("a/b/c" = TRUE) should result in:

#> $a
#> $a$b
#> $a$b$c
#> [1] TRUE

I have a solution, but it feels pretty involved:

library(magrittr)
nested_list <- function(input) {
  nms <- names(input)
  ret <- lapply(1:length(input), function(level) {
    value <- input[[level]]

    name <- nms[level] %>%
      strsplit("/") %>%
      unlist()
    name_vec <- NULL
    ret <- list()

    # Create nested list structure -----
    for (ii in name) {
      name_vec <- c(name_vec, ii)
      ret[[name_vec]] <- list()
    }

    # Assign leaf value -----
    ret[[name]] <- value

    ret
  })
  unlist(ret, recursive = FALSE)
}

Example runs

input <- c("a/b/c" = TRUE, "x/y/z" = FALSE)
nested_list(input)
#> $a
#> $a$b
#> $a$b$c
#> [1] TRUE
#> 
#> 
#> 
#> $x
#> $x$y
#> $x$y$z
#> [1] FALSE

input <- list("a/b/c" = TRUE, "x/y/z" = list(p = 1, q = 2))
nested_list(input)
#> $a
#> $a$b
#> $a$b$c
#> [1] TRUE
#> 
#> 
#> 
#> $x
#> $x$y
#> $x$y$z
#> $x$y$z$p
#> [1] 1
#> 
#> $x$y$z$q
#> [1] 2
Created on 2018-10-18 by the [reprex package][1] (v0.2.0).

Disclaimer

I did look around a bit (e.g. question 1, question 2), but I didn't quite find what I was looking for.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I wrote a recursive function which does something similar

recur.list <- function(x, y) {
  if(length(x) == 1)
    setNames(list(y), x[1])
  else
    setNames(list(recur.list(x[-1], y)), x[1])
}

listed_list.dirs <- function(input) {
   vec <- strsplit(names(input), "/")
   mapply(recur.list, vec, input)
}

Basically recur.list is a recursive function which creates a named nested list based on the number of "/" whereas listed_list.dirs splits the name on "/" and creates a separate vector of characters for each of the input.

input <- c("a/b/c" = TRUE, "x/y/z" = FALSE)
listed_list.dirs(input)
#$a
#$a$b
#$a$b$c
#[1] TRUE

#$x
#$x$y
#$x$y$z
#[1] FALSE

input <- list("a/b/c" = TRUE, "x/y/z" = list(p = 1, q = 2))
listed_list.dirs(input)
#$a
#$a$b
#$a$b$c
#[1] TRUE

#$x
#$x$y
#$x$y$z
#$x$y$z$p
#[1] 1

#$x$y$z$q
#[1] 2

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...