user2909302 user2909302 - 2 months ago 8
R Question

interleave nested ist of vectors in r with string padding based on max nchar in innermost nest

I have a nested list of vectors in r where each vector has a different count of elements and each element contains a string of differing length as follows:

x <- list(
A=list(
c("11","11","11111","111","1111111111","11","11"),
c("11","1111","11","111","11","111"),
c("1111","111","1111") ),
B=list(
c("000","00","0","00","00000","00"),
c("00","000","00","0000","0"),
c("0000000","00","00") ) )

> x
$A
$A[[1]]
[1] "11" "11" "1111" "111" "1111111111" "11" "11"

$A[[2]]
[1] "11" "1111" "11" "1111" "11" "111"

$A[[3]]
[1] "1111" "111" "1111"


$B
$B[[1]]
[1] "000" "00" "0" "00" "00000" "00"

$B[[2]]
[1] "00" "000" "00" "0000" "0"

$B[[3]]
[1] "0000000" "00" "00"


step 1: I would like to print out the list with the nth element of each nested list being on the nth line in an interleaved way with the odd elements of the nth line from A and the even elements from B for example the first row would be


11000110011111011100111111111100000110011


step2: I would like to pad each element with spaces based on the max nchar for that position in the nested list for A and B separately so in this example for list A the max nchar of the 1st element is 4, the max nchar of the 2nd is also 4 the max nchar of the 3rd is 5, the max nchar of the 4th is 3 etc. but for B the max nchar for the 1st element is 7, for the 2nd is 3 etc. The desired output would be:

"11 000 11 00 111110 11100 11111111110000011 0011"
"11 00 111100011 00111000011 0 111"
"11110000000111 00 1111 00"


Trying to investigate I found this on interleaving two lists, but it will not interleave the nested part of the lists:

c(rbind(x$A,x$B))


yields

> c(rbind(x$A,x$B))
[[1]]
[1] "11" "11" "1111" "111" "1111111111" "11" "11"

[[2]]
[1] "000" "00" "0" "00" "00000" "00"

[[3]]
[1] "11" "1111" "11" "1111" "11" "111"

[[4]]
[1] "00" "000" "00" "0000" "0"

[[5]]
[1] "1111" "111" "1111"

[[6]]
[1] "0000000" "00" "00"


but I need something that will interleave the inner elements as well as pad them and I can't wrap my brain around how to do that with lapply/sapply/rapply etc.

In my data length(x$A) == length(x$B) and length(x$A[[n]]) == length(x$B[[n]])+1 so there will be no missing elements for interleaving

Answer

It should be convenient to elongate each element with a sufficient number of "" to conveniently find the maximum elementwise nchar and, later, rbind to interleave as in the linked post:

n = do.call(max, lapply(x, lengths))
x2 = lapply(x, function(ab) lapply(ab, function(x) c(x, rep_len("", n - length(x)))))

Then find the 'parallel' maximum nchar for each element:

ncx2 = lapply(x2, function(x) unlist(.mapply(max, lapply(x, nchar), NULL)))

and right-pad with spaces, accordingly:

x3 = Map(function(elt, nc) lapply(elt, function(x) sprintf("%-*s", nc, x)), x2, ncx2)

Finally, interleave the elements using the alternative of rbind and format the output appropriately:

.mapply(function(...) trimws(paste(c(rbind(...)), collapse = "")), x3, NULL)
#[[1]]
#[1] "11  000    11  00 111110 11100  11111111110000011 0011"
#
#[[2]]
#[1] "11  00     111100011   00111000011        0    111"
#
#[[3]]
#[1] "11110000000111 00 1111 00"

If x has, only, two elements, it could be more convenient to store a = x$A; b = x$B and duplicate parts of code to avoid the extra nested lapply/mapply compilcated calls.