1

I've got a list of vectors that take this form:

> g
[[1]]
 [1] "L"  "14" "L"  "39" "L"  "61" "B"  "0"  "L"  "15" "L"  "59" "W"  "64"

[[2]]
[1] "L"  "62" "D"  "31" "L"  "10" "L"  "30" "B"  "0"  "D"  "45" "L"  "43"

[[3]]
 [1] "H"  "0"  "L"  "11" "L"  "35" "W"  "45" "H"  "0"  "L"  "40" "L"  "42"

My goal is to use mapply on this structure and turn each of the 14 columns into a vector. The first column would be:

[[1]]
[1] "L"

[[2]]
[1] "L"

[[3]]
[1] "H"

And the second column would be:

[[1]]
[1] "14"

[[2]]
[1] "62"

[[3]]
[1] "0"

and so on. I suspect the structure would be a matrix (?) but I'm not sure. I used a lot of lapply and stringr's str_extract_all with regex to get this point but I am unsure how to proceed. I suspect the function would use a pattern like: "[A-Z]{1}" for the text and "[:digit:]{1}" and I know that mapply can return a matrix but I don't know where to begin.

Uwe
  • 41,420
  • 11
  • 90
  • 134
jmb277
  • 558
  • 4
  • 19
  • 1
    Using regexs here makes no sense. Perhaps it would be helpful to explain where this data is coming from (e.g., csv file, web scrape, manually-entered) and how you need to use it (e.g., plot it with `pkg::xyz()`). (And for clarity: your first block is a simple `list`, where each element is a `character` vector (not list). Your second and third blocks are both the same: a simple `list`, each element is a `character` vector (of length 1). – r2evans Feb 26 '17 at 01:05
  • I don't know R - but I agree with @r2evans regex seems overkill here, a quick bit of googling lead me to this: http://stackoverflow.com/questions/8464312/convert-comma-separated-entry-to-columns which seems like it's fairly close, but I'm not going to pretend I know R and try and change to suit your scenario exactly. – Theo Feb 26 '17 at 01:10
  • It's one small part of a much larger set of patterns that are taking apart a file - this is just one section of it. I'm basically looking for the `function` that outputs the this as a matrix or a series of lists. – jmb277 Feb 26 '17 at 01:32
  • 1
    There was a comment (since deleted) that suggested `do.call(rbind, g)`. It turns this `g` into a neat `matrix`. But you say you want each of the columns as a vector, so something like `lapply(seq_along(g[[1]]), function(i) sapply(g, `[[`, i))` gives that, but then you mention *"return a matrix"*, so I am very confused between what you say, what you need, and what you describe. – r2evans Feb 26 '17 at 01:39
  • apologies - I am still working out how these structures are described. I could probably work with either a matrix or a list: It seems like `do.call(rbind, g)` also worked perfectly and appears to be the same structure, too. I'll have to read up on `do.call(rbind, ...)` - Thank you! – jmb277 Feb 26 '17 at 01:51
  • See, also, a similar post [here](http://stackoverflow.com/questions/30164803/fastest-way-to-transpose-a-list-in-r-rcpp) – alexis_laz Feb 26 '17 at 12:56
  • you could do g %>% unlist(use.names = F) %>% matrix(nrow = 14) %>% t – Tom Greenwood May 10 '19 at 17:18

2 Answers2

1

Here is a solution using mapply

g <- list()
g[[1]] <- c("L",  "14", "L",  "39", "L",  "61", "B",  "0",  "L",  "15", "L",  "59", "W",  "64")
g[[2]] <- c("L",  "62", "D",  "31", "L",  "10", "L",  "30", "B",  "0",  "D",  "45", "L",  "43")
g[[3]] <- c("H",  "0",  "L",  "11", "L",  "35", "W",  "45", "H",  "0",  "L",  "40", "L",  "42")

Consider simple case where you want to extract first element in each list element, you can use lapply:

lapply(g, function (x) x[1])

Now we can use mapply to iterate:

lengths(g) # returns length of each element in the list
g2 <- mapply(function(y) lapply(g, function (x) x[y]), 1:lengths(g)[1])
g2

#      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14]
# [1,] "L"  "14" "L"  "39" "L"  "61" "B"  "0"  "L"  "15"  "L"   "59"  "W"   "64" 
# [2,] "L"  "62" "D"  "31" "L"  "10" "L"  "30" "B"  "0"   "D"   "45"  "L"   "43" 
# [3,] "H"  "0"  "L"  "11" "L"  "35" "W"  "45" "H"  "0"   "L"   "40"  "L"   "42" 

g2[,1]
# [[1]]
# [1] "L"

# [[2]]
# [1] "L"

# [[3]]
# [1] "H"

unlist(g2[,1])
# [1] "L" "L" "H"
Djork
  • 3,319
  • 1
  • 16
  • 27
  • 4
    `do.call(rbind, g)` gets to the matrix a little shorter/faster (copied from another comment, since deleted). – r2evans Feb 26 '17 at 01:40
  • _this_ is it, dude! Thank you! `lengths()` will come in handy. Quick follow-up: the form: `function (x) x[1]` in `lapply(g, function (x) x[1])` would that be the same as: `function (x){ x[1]}`? – jmb277 Feb 26 '17 at 01:44
  • good call of do.call r2evans, I forgot about that. @jmb277, {} allows you to group statements, allowing you to place multiple statements within the function body. – Djork Feb 26 '17 at 02:09
1

As alternative to do.call(rbind, g), we can use the fact that a data.frame actually is a list of vectors where all vectors have the same lengths. So, the given structure gcan be converted to a data.frame which is then transposed yielding a matrix as requested.

Reproduce the data:

g <- list(
  c("L",  "14", "L",  "39", "L",  "61", "B",  "0",  "L",  "15", "L",  "59", "W",  "64"),
  c("L",  "62", "D",  "31", "L",  "10", "L",  "30", "B",  "0",  "D",  "45", "L",  "43"),
  c("H",  "0",  "L",  "11", "L",  "35", "W",  "45", "H",  "0",  "L",  "40", "L",  "42")
)

Transform:

m <- t(as.data.frame(g))
dimnames(m) <- NULL   # remove deafault row names
m
#     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14]
#[1,] "L"  "14" "L"  "39" "L"  "61" "B"  "0"  "L"  "15"  "L"   "59"  "W"   "64" 
#[2,] "L"  "62" "D"  "31" "L"  "10" "L"  "30" "B"  "0"   "D"   "45"  "L"   "43" 
#[3,] "H"  "0"  "L"  "11" "L"  "35" "W"  "45" "H"  "0"   "L"   "40"  "L"   "42"

Access the columns:

m[, 1]
#[1] "L" "L" "H"
Uwe
  • 41,420
  • 11
  • 90
  • 134
  • This is also a fantastic answer that works great! I'll have to read up on `do.call` as the help section is pretty general! – jmb277 Feb 26 '17 at 14:17