I am looking to write a function that converts a nested list with an arbitrary length and number of levels into a string that may serve as input for a tree from the LaTeX package forest.
Below is how far I got. I managed to enclose every childless node in the tree in square brackets, but how do I retrieve the names of the intermediate nodes and concatenate them into a single string?
The string in the forest environment shows what I would like to convert my example list into.
\documentclass[a4paper]{article}
\usepackage{forest}
\begin{document}
<<list>>=
library("tidyverse")
nestedlist <- list("A"=list("B"=45:50, "C"=LETTERS[21:26],
"D"=list("E"=7:10, "F"=list("G","H"))))
squarebrackets <- function(x){
if(class(x) == "list")
map(x, squarebrackets)
else
paste0("[",x,"]") %>%
paste0(., collapse="")
}
squarebrackets(nestedlist)
@
\begin{forest}
[A[B[45][46][47][48][49][50]][C[U][V][W][X][Y][Z]][D[E[7][8][9][10]][F[G][H]]]]
\end{forest}
\end{document}
One approach is to take advantage of the hierarchy of the names automatically created by unlist(). This will also make F=c("G", "H") and F=list("G", "H") be treated in the same way.
The following example will not allow for numbers in the node names, and the node names must be unique. This could perhaps be improved upon by using a rapply() approach instead.
Define alternative squarebrackets
squarebracketsAlt <- function(inlist){
#create the name hierarchy
storeList <- unlist(inlist)
#get unique names which represents levels in hierarchy
uniqueNames <- unique(unlist(strsplit(gsub("[0-9]", "", names(storeList)), "\\.")))
#keep the names to search for length of node brackets
vecNames <- names(storeList)
storeVec <- paste0("[", storeList, "]")
names(storeVec) <- vecNames
for(i in uniqueNames){
#determine the two positions of the node brackets
whereBrack <- grep(paste0("\\.",i, "\\."),
paste0(".", gsub("[0-9]", "", names(storeVec)), "."))
#add the start bracket and node name to vector
storeVec <- append(storeVec, paste0("[", i), after=(whereBrack[1]-1))
#add the end bracket to vector
storeVec <- append(storeVec, paste0("]") , after=(whereBrack[length(whereBrack)]+1))
}
#collapse and output
cat(paste(storeVec, collapse=""))
}
Try it on your nested list:
nestedlist <- list("A"=list("B"=45:50, "C"=LETTERS[21:26],
"D"=list("E"=7:10, "F"=list("G","H"))))
squarebracketsAlt(nestedlist)
output:
[A[B[45][46][47][48][49][50]][C[U][V][W][X][Y][Z]][D[E[7][8][9][10]][F[G][H]]]]

Example larger hierarchy:
nestedlist1 <- list("Ad fe"=list("B"=45:50, "C"=list("U"=letters[1:10],LETTERS[22:26]),
"D"=list("E"=7:10, "F"=list("G"=list("ZZ foo"=list("AA bar"=c(1:10),2,3,4,5)),"H", "C"))))
squarebracketsAlt(nestedlist1)
output:
[Ad fe[B[45][46][47][48][49][50]][C[U[a][b][c][d][e][f][g][h][i][j]][V][W][X][Y][Z]][D[E[7][8][9][10]][F[G[ZZ foo[AA bar[1][2][3][4][5][6][7][8][9][10]][2][3][4][5]]][H][C]]]]

Real life example:
nestedlist2 <- list("Main Area"=
list("Fishing vessel"=c("trawler", "line", "skipper"), "Oil tanker"=c("Large", "Small", "Medium size"=
list("Barents Sea", "Norwegian Sea", "Kara Sea", "Greenland"))))
squarebracketsAlt(nestedlist2)
output:
[Main Area[Fishing vessel[trawler][line][skipper]][Oil tanker[Large][Small][Medium size[Barents Sea][Norwegian Sea][Kara Sea][Greenland]]]]

Example with leading numbers:
squarebracketsAltNum <- function(inlist){
#create the name hierarchy
storeList <- unlist(inlist)
#get unique names which represents levels in hierarchy
uniqueNames <- unique(paste(gsub("[A-z].*", "", unlist(strsplit(names(storeList), "\\."))),
unlist(strsplit(gsub("[0-9]", "", names(storeList)), "\\.")), sep=""))
#keep the names to search for length of node brackets
vecNames <- names(storeList)
storeVec <- paste0("[", storeList, "]")
names(storeVec) <- vecNames
k <- 1
for(i in uniqueNames){
cat(i, "\n")
#determine the two positions of the node brackets
whereBrack <- grep(paste0("\\.",i),
paste0(".", names(storeVec)))
#change position of number and character
namePaster <- unique(paste(unlist(strsplit(gsub("[0-9]", "", names(storeList)), "\\.")),
gsub("[A-z].*", "", unlist(strsplit(names(storeList), "\\."))), sep=""))[k]
#add the start bracket and node name to vector
storeVec <- append(storeVec, paste0("[", namePaster), after=(whereBrack[1]-1))
#add the end bracket to vector
storeVec <- append(storeVec, paste0("]") , after=(whereBrack[length(whereBrack)]+1))
k <- k+1
}
#collapse and output
cat(paste(storeVec, collapse=""))
}
No space between number and word/sentence. Fiddle with regexp to fix:
nestedlist <- list("100A"=list("4B"=45:50, "3C"=LETTERS[21:26],
"D"=list("E"=7:10, "78F"=c("G","H"))))
squarebracketsAlt(nestedlist)
Output:
[A100[B4[45][46][47][48][49][50]][C3[U][V][W][X][Y][Z]][D[E[7][8][9][10]][F78[G][H]]]]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With