How to use lapply to specific indices of a list? - r

When using lapply to apply a function to a list, how would I do this for every other four elements in the list?
For example if i have list of length 100, how would I apply my function to list[1], list[5], list[9], list[13] and so on?

Use lapply on the subset you're interested in.
> l <- as.list(1:15)
> lapply(l[seq(1,length(l),by=4)], identity)
[[1]]
[1] 1
[[2]]
[1] 5
[[3]]
[1] 9
[[4]]
[1] 13
Or, if you want to replace the values in the original list:
s <- seq(1,length(l),by=4)
l[s] <- lapply(l[s], function(x) x*2)

Or use (Using #Joshua Ulrich's data)
s1 <- (seq_along(l)-1)%%4+1==1
l[s1]
# [[1]]
#[1] 1
#[[2]]
#[1] 5
#[[3]]
#[1] 9
#[[4]]
#[1] 13
Or
s2 <- c(TRUE, rep(FALSE,3)) # The logical index will recycle to the length of `l`
It would do similar to the one below:
rep(s2, length.out=length(l))
# [1] TRUE FALSE FALSE FALSE TRUE FALSE FALSE FALSE TRUE FALSE FALSE FALSE
#[13] TRUE FALSE FALSE
l[s2]
# [[1]]
#[1] 1
#[[2]]
#[1] 5
#[[3]]
#[1] 9
#[[4]]
#[1] 13
and then use lapply

Related

How to turn a vector into a list with known nest structure in R?

I want to turn a x dimensional vector into a nested list that has x elements. The nested list should have the same nest structure as a known list. Is there a simple way to do this?
For example, the vector to be transformed is
vector <- rnorm(10)
while the list with known structure is
list <- list( list(rnorm(2),rnorm(2)),
list(rnorm(3),rnorm(3)) )
[[1]]
[[1]][[1]]
[1] -1.113833 1.158779
[[1]][[2]]
[1] 0.09773685 -1.62518666
[[2]]
[[2]][[1]]
[1] -1.134478 -1.091703 -0.109145
[[2]][[2]]
[1] -0.5181986 -1.9268952 -0.8527101
Another similar situation is that I may know the length of each sublist
length_list <- list( list(2,2), list(3,3) )
You can use relist.
x <- 1:10
lst <- list( list(rnorm(2),rnorm(2)),
list(rnorm(3),rnorm(3)) )
relist(x, lst)
#[[1]]
#[[1]][[1]]
#[1] 1 2
#
#[[1]][[2]]
#[1] 3 4
#
#
#[[2]]
#[[2]][[1]]
#[1] 5 6 7
#
#[[2]][[2]]
#[1] 8 9 10
Or for the other case create a list with rapply.
x <- 1:10
length_list <- list( list(2,2), list(3,3) )
relist(x, rapply(length_list, rep, x=0, how="list"))
#[[1]]
#[[1]][[1]]
#[1] 1 2
#
#[[1]][[2]]
#[1] 3 4
#
#
#[[2]]
#[[2]][[1]]
#[1] 5 6 7
#
#[[2]][[2]]
#[1] 8 9 10

Count the number of `TRUE` in a list

I have a list as such
$`1`
[1] TRUE
$`5`
[1] TRUE
$`14`
[1] FALSE
$`17`
[1] TRUE
$`19`
[1] TRUE
$`20`
[1] TRUE
Is there an easy way to count the total number of TRUE values in the list?
I tried doing this trucount <- function(z){sum(z,na.rm = TRUE)} , but it doesn't work.
In the above example, the solution would return 5
You can use isTRUE():
> ll = list(`1`=TRUE, `5`=TRUE, `14`=TRUE, `17`=TRUE, `19`=TRUE, `20`=TRUE, `21`=FALSE)
> length(which(sapply(ll, isTRUE)))
[1] 6

Identify the location of a special element in a vector which each elements contain several elements

a1 <- c("COL8A1/PRG4/DPT/ASPN/PODN/CCN1/BGN/MXRA5/MGP/COL16A1/MFAP5/THBS1/MATN2/AEBP1/MFAP4/SRPX/COL14A1/FGL2/ABI3BP/THBS2/LAMA4/COL8A2/FMOD/CTHRC1/COL12A1/OGN/PRELP/LTBP2/ANOS1")
a2 <- c("DPYSL3/CTSG/CCN5/CCN1/BGN/PCOLCE2/SLIT2/CCDC80/RSPO3/CFH/LYVE1/SFRP1/SLIT3/THBS1/SULF1/GPNMB/CCN2/SELP/THBS2/SPOCK2/RSPO1/PRELP/TGFBR3/LTBP2/LPL/HBEGF/ANOS1/NRP2/TGFBR2/CLEC3B/LXN/THBS4/SERPINE2/POSTN")
a3 <- c("CTSG/CCN5/CCN1/PCOLCE2/SLIT2/CCDC80/RSPO3/CFH/SFRP1/SLIT3/THBS1/GPNMB/CCN2/SELP/THBS2/RSPO1/PRELP/TGFBR3/LTBP2/LPL/HBEGF/ANOS1/NRP2/CLEC3B/LXN/THBS4/SERPINE2/POSTN/COMP/FBLN7/ECM2/SMOC2/SOD3")
a4 <- c("PDLIM3/MYH11/CNN1/SORBS1/FLNC/MYOM1/NEXN/ADD2/MYOZ3/MYLK/TAGLN/SHANK3/SYNE3/GSN/FAM107A/COBLL1/AIF1/LMOD1/TPM2/FLNA/SNCA/SPTBN1/TNNT3/VASH2/GMFG/S100A4/ENC1/KLHL4/WASF3/LMOD3/CORO1C/HCLS1/ABLIM2/TPM1/CALD1/ABLIM3/LIMA1/SVIL/FXYD5/NOS3/TNS1/SMTN/PLS3/MYH10/ENAH/WAS/EPB41L2/PLEC/MYO18A/ANG/MYO1C/MAP1A/MYO1F/EPB41L3/MTSS1/MAP1B/SNTA1/DMD/CNN3/PKNOX2")
b <- c(a1,a2,a3,a4)
If I have a special element,'CCN1', how can I identify which element of vector b has 'CCN1', and the location in each vector,a1,a2,a3 and a4. I can see 'CCN1' is the sixth one of a1, the forth one of a2, the third one of a3.
To identify which element of vector b has CCN1 grep or grepl coluld be used:
grep("CCN1", b)
#[1] 1 2 3
grepl("CCN1", b)
#[1] TRUE TRUE TRUE FALSE
To get the position the string need to be split on / using strsplit and than again grep could be used.
lapply(strsplit(b, "/", TRUE), grep, pattern="CCN1")
#[[1]]
#[1] 6
#
#[[2]]
#[1] 4
#
#[[3]]
#[1] 3
#
#[[4]]
#integer(0)
library(stringr)
str_which("CCN1", unlist(str_split(a1, "/")))
[1] 6
Or more generally
library(purrr)
library(stringr)
map(b, function(x) str_which("CCN1", unlist(str_split(x, "/"))))
[[1]]
[1] 6
[[2]]
[1] 4
[[3]]
[1] 3
[[4]]
integer(0)

How to merge two lists based on object indices - keeping attributes?

I want to merge two lists keeping the index of each object:
mylist<-list(1,NULL,2)
otherlist<-list(NULL,3,NULL,4,5,6)
# Desired
list(1,3,2,4,5,6)
# my try:
suppressWarnings(mapply(c, mylist, otherlist) )
Answer should be universal
EDIT: In order to avoid proliferation of similar questions. I decided to request here also the possibility of keeping attributes (preferably with base).
mylist<-list(1,NULL,2)
attr(mylist[[1]],"at")<-"a"
attr(mylist[[3]],"at")<-"c"
otherlist<-list(NULL,3,NULL,4,5,6)
attr(otherlist[[2]],"at")<-"b"
attr(otherlist[[4]],"at")<-"d"
attr(otherlist[[5]],"at")<-"e"
attr(otherlist[[6]],"at")<-"f"
Here is an option where we create a logical index with lengths (which will return 0 when there is NULL) and use to assign the elements with mylist unlisted
otherlist[lengths(otherlist) == 0] <- unlist(mylist)
otherlist
#[[1]]
#[1] 1
#[[2]]
#[1] 2
#[[3]]
#[1] 3
#[[4]]
#[1] 4
#[[5]]
#[1] 5
#[[6]]
#[1] 6
If we need to use Map, make sure the lengths are the same for the corresponding elements
otherlist[seq_along(mylist)] <- Map(c, otherlist[seq_along(mylist)], mylist)
Update
For the updated example
i1 <- sapply(otherlist, is.null)
i2 <- !sapply(mylist, is.null)
otherlist[i1] <- mylist[i2]
otherlist
#[[1]]
#[1] 1
#attr(,"at")
#[1] "a"
#[[2]]
#[1] 3
#attr(,"at")
#[1] "b"
#[[3]]
#[1] 2
#attr(,"at")
#[1] "c"
#[[4]]
#[1] 4
#attr(,"at")
#[1] "d"
#[[5]]
#[1] 5
#attr(,"at")
#[1] "e"
#[[6]]
#[1] 6
#attr(,"at")
#[1] "f"
foo <- function(l1, l2) {
out <- vector(mode = "list", length = max(length(l1), length(l2)))
out[seq_along(l1)] <- l1
out[!lengths(out)] <- l2[!lengths(out)]
out
}
foo(mylist, otherlist2)
# [[1]]
# [1] 1
# attr(,"at")
# [1] "a"
#
# [[2]]
# [1] 3
# attr(,"at")
# [1] "b"
#
# [[3]]
# [1] 2
# attr(,"at")
# [1] "c"
#
# [[4]]
# [1] 5
# attr(,"at")
# [1] "e"
#
# [[5]]
# [1] 6
# attr(,"at")
# [1] "f"

Convert a vector into a specialised list efficiently

I'm looking for a more efficient way to get from my current input to my expected output.
Input
vec <- 1:4
Expected output
[[1]]
[1] 1 2 3 4
[[2]]
[1] 1
[[3]]
[1] 2
[[4]]
[1] 3
[[5]]
[1] 4
Current solution:
lis <- list()
lis[2:5] <- as.list(vec)
lis[[1]] <- vec
We can do
c(list(vec), as.list(vec))
#[[1]]
#[1] 1 2 3 4
#[[2]]
#[1] 1
#[[3]]
#[1] 2
#[[4]]
#[1] 3
#[[5]]
#[1] 4

Resources