0

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

Community
  • 1
  • 1
user2909302
  • 103
  • 8

2 Answers2

1

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.

Community
  • 1
  • 1
alexis_laz
  • 12,884
  • 4
  • 27
  • 37
0

We can try

lapply(seq(lengths(x)[1]), function(i)  {
        x1 <- c(x[[1]][i], x[[2]][i])
       x2 <- c(do.call(rbind, lapply(x1, `length<-`, max(lengths(x1)))))
       paste(replace(x2, is.na(x2), ""), collapse="")})
#[[1]]
#[1] "11000110011111011100111111111100000110011"

#[[2]]
#[1] "1100111100011001110000110111"

#[[3]]
#[1] "1111000000011100111100"

If we are using packages, then transpose (from purrr) and stri_list2matrix (from stringi) can be used

library(purrr)
library(stringi)
transpose(x) %>%
        map(stri_list2matrix, byrow=TRUE, fill="") %>%
        map(paste, collapse="")
#[[1]]
#[1] "11000110011111011100111111111100000110011"

#[[2]]
#[1] "1100111100011001110000110111"

#[[3]]
#[1] "1111000000011100111100"

For the second step, we guess this works

lst2 <- lapply(x, function(y) {l1 <- lapply(y, nchar)
    do.call(pmax, c(lapply(l1, `length<-`, max(lengths(l1))), na.rm=TRUE))})
lst3 <- lapply(transpose(x), function(x) Map(function(y, z) 
       do.call(c, lapply(seq_along(y), function(i)
       formatC(y[i], width = z[1:length(y)][i], flag = "-"))), x, lst2))
lapply(lst3, function(x) paste(stri_list2matrix(x, fill="", byrow=TRUE), collapse=""))
#[[1]]
#[1] "11  000    11  00 111110 11100  11111111110000011 0011"

#[[2]]
#[1] "11  00     111100011   00111000011        0    111"

#[[3]]
#[1] "11110000000111 00 1111 00"
akrun
  • 874,273
  • 37
  • 540
  • 662
  • Thanks @akrun - the first part works great but I got this error when trying to run part 2: `lst3 <- lapply(transpose(x), function(x) Map(function(y, z) do.call(c, lapply(seq_along(y), function(i) formatC(y[i], width = z[1:length(y)][i], flag = "-"))), x, lst2))` **Error in transpose(x) : Item 1 of list input is not an atomic vector** – user2909302 Sep 21 '16 at 18:46
  • 1
    @user2909302 sorry, there was typo (didn't copy the `})` (fixed it)` – akrun Sep 21 '16 at 18:49