Subsetting elements in list a based on elements list b - r

I have 2 lists:
c1 <- c("e","f","g","h")
c2 <- c("j","k","l","m")
list1 <- list(c1,c2)
i1 <- c(1,3)
i2 <- c(2,4)
list2 <- list(i1,i2)
I would like to subset the character vectors in list a based on integer vectors in list b. This way I would end up with a new list (list3) containing c1 (with only e and g) and c2 (with only k and m). I'm currently looking into the possibilities of plyr so the solution should preferably be with plyr. I tried something similar to this but to no avail.
list3 <- llply(list1, function (x) x[list2])

You could try with base R using Map, which would be more compact than the one with llply. Basically, you have two lists with same number of list elements and wanted to subset one each list element of the first list ("list1") based on the index list elements of ("list2"). Map will compare the corresponding elements of "list1" and "list2" and subset using [
Map(`[`, list1, list2)
which is the same as
Map(function(x,y) x[y], list1, list2)
Or using llply from plyr (you don't really need llply). This could be achieved with lapply itself. The key is to compare the corresponding elements of both lists and the possible way you can link both (when they have same elements) is to use seq_along which will get you the sequence of elements in one list (1:3) and use that index to get the corresponding elements of both list and then subset.
llply(seq_along(list1), function(i) list1[[i]][list2[[i]]])

Related

Pre-Processing / Formatting Data

I have two vectors in R:
list1 <- c("ABCDEF", "FEDCBA", "AA-BB-CCCC", "ABCDEFGH-IJK", "ZZZZ")
list2 <- c("ABCDEF", "FEDCBA:XA",
"AA-BB-CCCC-01","AA-BB-CCCC-21:ABC", "ABCDEFGH-IJK-1X",
"AKDWXFE-XXY")
I'd like to compare the two lists -- with list1 being the 'correct' list. If an item in list1 does not appear in list2, then print out 'Add [item in list1]'; if item in list2 is not in list1, then print out 'delete [item in list 2]'. I would like to find partial matches. For example, list 1 has 'FEDCBA' and list2 has 'FEDCBA:XA" -- this would be an acceptable partial match....same with list 2 having AA-BB-CCCC-21:ABC while list1 has AA-BB-CCCC (this is also an acceptable partial match).
It looks like a homework to me, but OK, let us make it a teaching moment.
First, let us find out which elements of list1 have matches in list2. We will use grepl for that, which returns a logical vector with one TRUE/FALSE value for each element of list2.
library(tidyverse)
list1_has_match <- map_lgl(list1, ~ any(grepl(., list2)))
msg <- sprintf("Add [%s]", list1[ !list1_has_match ])
In the above code, I use map_lgl to run the any(grepl(...)) expression for each element of list1 and return a logical vector. Any element that has a FALSE value in that vector is not present in list2 and should be added.
Next, we do the same – the other way around. However, we have still to use the elements of list1 as a pattern. This is why the next point gets a bit complicated. In each call within map_dfr, we are generating a named vector corresponding to one element of list1. However, since we use map_dfr, each of these vectors will be considered a row in a data frame. Thus, the columns of the result will correspond to the elemnts of list2.
map1 <- map_dfr(list1, ~ set_names(grepl(., list2), list2))
list2_has_match <- map_lgl(map1, any)
msg <- c(msg,
sprintf("delete [%s]", list2[ !list2_has_match ]))
And now print the messages
cat(msg, sep="\n")

R: choose elements from list based on values in vector with same names

[Probably this question already has an answer here, but I didn't manage to find one, also because I have some difficulty in formulating it concisely. Suggestions for reformulating the title of the question are appreciated.]
I have
a list of matrices with different numbers of rows,
a vector of integer values with the same names as the list's,
a list of names that appear in the list and vector above,
an integer variable telling which column to choose from those matrices.
Let's construct, as a working example:
mynames <- c('a', 'c')
mylist <- list(a=matrix(1:4,2,2), b=matrix(1:6,3,2), c=matrix(1:8,4,2))
myvec <- 2:4
names(myvec) <- names(mylist)
chooseCol <- 2
I'd like to construct a vector having as elements the rows taken from myvec and column chooseCol, for the names appearing in mynames. My attempt is
sapply(mynames, function(elem){mylist[[elem]][myvec[elem], chooseCol]})
which correctly yields
a c
4 8
but I was wondering if there's a faster, base (non-tidyverse) method of doing this.
Also important or relevant: the order of the names in mylist and myvec can be different, so I can't rely on position indices.
I would use mapply -
mapply(function(x, y) x[y, chooseCol], mylist[mynames], myvec[mynames])
#a c
#4 8

How to split a list of vectors to sub-lists by increasing order.

I have a list of n vectors. I would like to split it to sub-list where the number of the vectors at each list is different. The number of the vectors is increased sequentially from one list to another. For example,
if I have a list with 6 vectors. Then, I would like to split it to several list as follows:
The first list contains one vector. Then, the second list contains 2 vectors and so on. For example,
Suppose I have the list x as follows:
x <- list(x1=c(1,2,3), x2=c(1,4,3), x3=c(3,4,6), x4=c(4,8,4), x5=c(4,33,4), x6=c(9,6,7))
Then, I would like to split it into 3 lists,
list1 = x1
list2 = list(x2, x3)
list3 = list(x4,x5, x6)
I have similar question (How to splitting a list of vectors to small lists in decreasing order in r) but in a decreasing order.
How I can generate it to arbitrary number of vectors. For example, how if I have 10 or 20 vectors?
Any idea, please?
I'd stick them all in a list of lists
MyLists <- list()
i <- 1
for (inc in 1:3){
MyLists[[inc]] <- x[i:(i+inc-1)]
i <- i+inc
}
Now MyLists[[1]] is list1, etc.
Building off farnsy's answer, If you need each list in a separate indexed list in the global environment you could do something like this.
#your Stater list
x <- list(x1=c(1,2,3), x2=c(1,4,3), x3=c(3,4,6),
x4=c(4,8,4), x5=c(4,33,4), x6=c(9,6,7))
#using a paste parse eval approach to evaluate a string
i<-1
for(inc in 1:3){
eval(parse(text =
paste0("list", inc, "<-list(",
paste0("x$",names(x)[i:(i+inc-1)],collapse = ","),
")")
))
i <- i+inc
}

Transpose R Table

I am trying to transpose a table I have created from a list of lists.
Each nested list has this format:
list(storm_name=NA, storm_level=NA, file_date=NA, file_time=NA,
date=NA, time=NA, actual_or_forecast=NA, lat=NA, long=NA, max_wind=NA,
gusts=NA, eye_speed=NA, eye_location=NA, storm_end=NA)
In short, each row has 14 elements within it.
storm_df <- as.data.frame(matrix(unlist(list1), nrow=length(unlist(list1[1]))))
The code I have written above so far creates the table where the orientation is 14 rows x N (number of inner lists) columns whereas I would like it to be N rows x 14 columns.
Does anyone see what I am doing wrong?
Thanks in advance!
Let's use do.call, rbind, and lapply:
## data
l1 <- list(storm_name=NA, storm_level=NA, file_date=NA, file_time=NA,
date=NA, time=NA, actual_or_forecast=NA, lat=NA, long=NA, max_wind=NA,
gusts=NA, eye_speed=NA, eye_location=NA, storm_end=NA)
big_list <- list(l1, l1, l1)
## make data.frame
do.call('rbind', lapply(big_list, data.frame))
Stepping through this, first we run lapply on big_list, so for each item in big_list, we create a data.frame. Try data.frame(l1) to see the result of each call.
Then we use do.call('rbind', ...) because the lapply returns a lists of data.frames, we want to "stack" the data on top of each other.

Converting specific parts of lists to a dataframe

I have a large list of 2 elements containing lists of species containing lists of 25 vectors, resembling a set like this:
l1 <- list(time=runif(100), space=runif(100))
l2 <- list(time=runif(100), space=runif(100))
list1 <- list(test1=list(species1=l1, species2=l2),test2=list(species1=l1, species2=l2))
I think, its essentially a list of a list of lists.of vectors.
I want to create a data.frame from all space-vectors of all 'species' in just one of the two sublists:
final <- as.data.frame(cbind(unlist(list1[[2]]$species1$space), unlist(list1[[2]]$species2$space)))
names(final) <- names(list1[[2]])
Essentially, i need a loop/apply command that navigates me through list1[[2]]$species and picks all vectors called space.
Thank you very much!
We can use a nested loop to extract the 'space' elements
data.frame(lapply(list1, function(x)
sapply(x, "[", 'space')))

Resources