How to merge two lists in parallel in R? - r

I'm asking to how to merge two lists in parallel, not orderly append as below codes.
For example,
A <- list(c(1,2,3), c(3,4,5), c(6,7,8))
B <- list(c("a", "b", "c"), c("d", "e", "f"), c("g", "h", "i"))
As results,
[[1]]
[[1]][[1]]
[1] 1 2 3
[[1]][[2]]
[1] "a" "b" "c"
[[2]]
[[2]][[1]]
[1] 3 4 5
[[2]][[2]]
[1] "d" "e" "f"
[[3]]
[[3]][[1]]
[1] 6 7 8
[[3]][[2]]
[1] "g" "h" "i"

Using  Map simply:
Map(list,A,B)

A longer approach (not recursive yet, up to second level merging):
A <- list(c(1,2,3), c(3,4,5), c(6,7,8))
B <- list(c("a", "b", "c"), c("d", "e", "f"), c("g", "h", "i"))
mergepar <- function(x = A, y = B) { # merge two lists in parallel
ln <- max(length(x), length(y)) # max length
newlist <- as.list(rep(NA, ln)) # empty list of max length
for (i in 1:ln) { # for1, across length
# two level subsetting (first with [ and then [[, so no subscript out of bound error) and lapply
newlist[[i]] <- lapply(list(A, B), function(x) "[["("["(x, i), 1))
}
return(newlist)
}

Related

Applying split function to overlapping rows of a matrix

Suppose I have a matrix which looks like this:
[1] a b c
[2] d e f
[3] g h i
[4] j k l
[5] m n o
[6] p q r
Now I want to split this matrix into smaller ones with each 3 rows, starting from the first row, then the second, ..., so it looks like this in the end:
[1] a b c
[2] d e f
[3] g h i
[1] d e f
[2] g h i
[3] j k l
[1] g h i
[2] j k l
[3] m n o
...
I tried the following code, which didn't do it for me:
lapply(split(1:nrow(matrix),(1:nrow(matrix)-1) %/%3+1),
function(i) matrix[i,])
Can someone help me with this?
The split method showed in the OP's post will split into blocks of 3 rows and that will not be mutually exclusive. Whereas if we want to split in a way that each list element starts with each of the rows of the matrix and the next two rows, we can loop through the sequence of rows, get the sequence from that index to the next two and subset the matrix
lapply(head(seq_len(nrow(matrix)), -2), function(i) matrix[i:(i+2),])
#[[1]]
# [,1] [,2] [,3]
#[1,] "a" "b" "c"
#[2,] "d" "e" "f"
#[3,] "g" "h" "i"
#[[2]]
# [,1] [,2] [,3]
#[1,] "d" "e" "f"
#[2,] "g" "h" "i"
#[3,] "h" "k" "l"
#[[3]]
# [,1] [,2] [,3]
#[1,] "g" "h" "i"
#[2,] "h" "k" "l"
#[3,] "m" "n" "o"
[[4]]
[,1] [,2] [,3]
[1,] "h" "k" "l"
[2,] "m" "n" "o"
[3,] "p" "q" "r"
Or as #lmo suggested, another version of the above would be
lapply(seq_len(nrow(matrix) -2L) - 1L, function(x) matrix[x + 1:3,])
or another option is to create the splitting group with rollapply (from zoo) and then do the split
library(zoo)
grp <- rollapply(seq_len(nrow(matrix)), 3, FUN = I)
lapply(split(grp, row(grp)), function(i) matrix[i, ])
NOTE: matrix is a function name. It is better not to name objects with function names or other reserved words
data
matrix <- structure(c("a", "d", "g", "h", "m", "p", "b", "e", "h", "k",
"n", "q", "c", "f", "i", "l", "o", "r"), .Dim = c(6L, 3L))

assign names to each object inside a list using a vector r

I have this list:
mylist <- list(TRUE, LETTERS[1:3], 1:5)
which returns:
[[1]]
[1] TRUE
[[2]]
[1] "A" "B" "C"
[[3]]
[1] 1 2 3 4 5
I want to assign name to each object inside the list using a vector a<-c("a", "b", "c").
Expected output:
$a
[1] TRUE
$b
[1] "A" "B" "C"
$c
[1] 1 2 3 4 5
You could do the following:
mylist <- list(TRUE, LETTERS[1:3], 1:5)
names(mylist) <- c("a", "b", "c")
mylist
Returns:
$a
[1] TRUE
$b
[1] "A" "B" "C"
$c
[1] 1 2 3 4 5
Or to use the vector a you mention, it's the same idea:
a <- c("a", "b", "c")
names(mylist) <- a

Create a list from another list with R

I have a list of letters l
[1] a b c
[2] b c a b
and a vector v of letter too
[1] a
[2] b
My object is to take the letters of the vector v one by one and creating a new list that contains all the letter appearing after that letter.
For example
I take the first letter of v "a" and I create the list of letter appearing after "a" , And I got this :
[1] b c
[2] b
After i take the second letter or v which is "b"
and I add to the list :
[3] c
[4] c a b
So the final result is :
[1] b c
[2] b
[3] c
[4] c a b
I don't know how to do this, it seems complicated.
I have also a list of vector with this format
[[1]]
[1] a
[2] b
[3] c
[[2]]
[1] e
[2] g
A nested lapply:
lapply(v, function(v, l) lapply(l, function(x, v) {
if (!(v %in% x)) return(x) #the case of no match
x[-seq_len(which.max(x == v))]
}, v = v), l = l)
#[[1]]
#[[1]][[1]]
#[1] "b" "c"
#
#[[1]][[2]]
#[1] "b"
#
#
#[[2]]
#[[2]][[1]]
#[1] "c"
#
#[[2]][[2]]
#[1] "c" "a" "b"
Here is one approach using lapply.
dat <- list( c("a", "b", "c"), c("b", "c", "a", "b"))
v <- c("a", "b")
result <- list()
for (l in v) {
result[[l]] <- lapply(dat, function(z) z[(which(z == l)[1] + 1):length(z)])
}
result

From list of vector to list with R

I have a list of vector :
[[1]]
[1] a
[2] f
[3] e
[4] a
[[2]]
[1] f
[2] f
[3] e
I would like to know if is there a way to transform it in a list (simple list of characters) like this :
[1] a f e a
[2] f f e
Thank you
You can use unlist
l1 <- list(list("a", "f", "e", "a"),
list("f", "f", "e"))
lapply(l1, unlist)
[[1]]
[1] "a" "f" "e" "a"
[[2]]
[1] "f" "f" "e"

How to extract unique levels from 2 columns in a data frame in r

I have the data.frame
df<-data.frame("Site.1" = c("A", "B", "C"),
"Site.2" = c("D", "B", "B"),
"Tsim" = c(2, 4, 7),
"Jaccard" = c(5, 7, 1))
# Site.1 Site.2 Tsim Jaccard
# 1 A D 2 5
# 2 B B 4 7
# 3 C B 7 1
I can get the unique levels for each column using
top.x<-unique(df[1:2,c("Site.1")])
top.x
# [1] A B
# Levels: A B C
top.y<-unique(df[1:2,c("Site.2")])
top.y
# [1] D B
# Levels: B D
How do I get the unique levels for both columns and turn them into a vector i.e:
v <- c("A", "B", "D")
v
# [1] "A" "B" "D"
top.xy <- unique(unlist(df[1:2,]))
top.xy
[1] A B D
Levels: A B C D
Try union:
union(top.x, top.y)
# [1] "A" "B" "D"
union(unique(df[1:2, c("Site.1")]),
unique(df[1:2, c("Site.2")]))
# [1] "A" "B" "D"
You can get the unique levels for the firs two collumns:
de<- apply(df[,1:2],2,unique)
de
# $Site.1
# [1] "A" "B" "C"
# $Site.2
# [1] "D" "B"
Then you can take the symmetric difference of the two sets:
union(setdiff(de$Site.1,de$Site.2), setdiff(de$Site.2,de$Site.1))
# [1] "A" "C" "D"
If you're intrested in just two first two rows (as in your example):
de<- apply(df[1:2,1:2],2,unique)
de
# Site.1 Site.2
# [1,] "A" "D"
# [2,] "B" "B"
union(de[,1],de[,2])
# [1] "A" "B" "D"

Resources