Assume that this is my list
a <- list(c(1,2,4))
a[[2]] <- c(2,10,3,2,7)
a[[3]] <- c(2, 2, 14, 5)
How do I subset this list to exclude all the 2's. How do I obtain the following:
[[1]]
[1] 1 4
[[2]]
[1] 10 3 7
[[3]]
[1] 14 5
My current solution:
for(j in seq(1, length(a))){
a[[j]] <- a[[j]][a[[j]] != 2]
}
However, this approach feels a bit unnatural. How would I do the same thing with a function from the apply family?
Thanks!
lapply(a, function(x) x[x != 2])
#[[1]]
#[1] 1 4
#
#[[2]]
#[1] 10 3 7
#
#[[3]]
#[1] 14 5
Using lapply you can apply the subset to each vector in the list. The subset used is, x[x != 2].
Or use setdiff by looping over the list with lapply
lapply(a, setdiff, 2)
#[[1]]
#[1] 1 4
#[[2]]
#[1] 10 3 7
#[[3]]
#[1] 14 5
Related
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
I have a list of a list with high complicated data. I would like to compare the values of each list and extract the smallest values. For simplicity, I provide a similar example.
s <- c(1,2,3)
ss <- c(4,5,6)
S <- list(s,ss)
h <- c(4,8,7)
hh <- c(0,3,4)
H <- list(h,hh)
HH <- list(S,H)
I would like to compare the element of each list with the element of the corresponding list and extract the smallest values. For example, the following are the values of HH list.
> HH
[[1]]
[[1]][[1]]
[1] 1 2 3
[[1]][[2]]
[1] 4 5 6
[[2]]
[[2]][[1]]
[1] 4 8 7
[[2]][[2]]
[1] 0 3 4
Now, I would like to compare
[[1]]
[[1]][[1]]
[1] 1 2 3
with
[[2]]
[[2]][[1]]
[1] 4 8 7
For example, 1 < 4, so I will select 1. For the second element, 2 < 8, so I will select 2. So, I would like to compare the elements of [[1]][[1]] with the elements of [[2]][[1]], and [[1]][[2]] with [[2]][[2]].
Then, I would like to print the name of the list. For example,
I expected to have similar to the following:
1 < 4, the first element of the first model is selected.
We could use a general solution (i.e. if there are many list elements) transpose from purrr to rearrange the list elements, and then use max.col to get the index
library(magrittr)
library(purrr)
HH %>%
transpose %>%
map(~ .x %>%
invoke(cbind, .) %>%
multiply_by(-1) %>%
max.col )
#[[1]]
#[1] 1 1 1
#[[2]]
#[1] 2 2 2
Or using base R
do.call(Map, c(f = function(...) max.col(-1 * cbind(...)), HH))
#[[1]]
#[1] 1 1 1
#[[2]]
#[1] 2 2 2
Maybe you can try this -
Map(function(x, y) as.integer(x > y) + 1, HH[[1]], HH[[2]])
#[[1]]
#[1] 1 1 1
#[[2]]
#[1] 2 2 2
This gives the position of the element selected.
What is the most elegant way to split a vector into n-Elements based on a condition?
Every separate true-block should go into its own list element. All the false elements get thrown away.
example1:
vec <- c(1:3,NA,NA,NA,4:6,NA,NA,NA,7:9,NA)
cond <- !is.na(vec)
result = list(1:3,4:6,7:9)
example2:
vec_2 <- c(3:1,11:13,6:4,14:16,9:7,20)
cond_2 <- vec_2 < 10
results_2 = list(3:1,6:4,9:7)
It would be great to have a general solution for a vector vec and a relating condition cond.
My best try:
res <- split(vec,data.table::rleidv(cond))
odd <- as.logical(seq_along(res)%%2)
res[if(cond[1])odd else !odd]
I guess this should work generally:
> split(vec[cond], data.table::rleid(cond)[cond])
$`1`
[1] 1 2 3
$`3`
[1] 4 5 6
$`5`
[1] 7 8 9
Let's make it a function:
> f <- function(vec, cond) split(vec[cond], data.table::rleid(cond)[cond])
> f(vec_2, cond_2)
$`1`
[1] 3 2 1
$`3`
[1] 6 5 4
$`5`
[1] 9 8 7
Here is a base R option with rle
grp <- with(rle(cond), rep(seq_along(values) * NA^ !values, lengths))
split(vec[cond], grp[cond])
#$`1`
#[1] 1 2 3
#$`3`
#[1] 4 5 6
#$`5`
#[1] 7 8 9
Similarly with 'vec_2'
grp <- with(rle(cond_2), rep(seq_along(values) * NA^ !values, lengths))
split(vec_2[cond_2], grp[cond_2])
#$`1`
#[1] 3 2 1
#$`3`
#[1] 6 5 4
#$`5`
#[1] 9 8 7
Or create a grouping variable with cumsum and diff
grp <- cumsum(c(TRUE, diff(cond) < 0)) * NA^ is.na(vec)
In R, I am calling unlist on a list to convert to a vector. However, some of my list elements are empty, and hence returns integer(0). The unlist() function by default drops this. How can I return a vector that has NA where the list is empty? I have created a reproducible example:
> ex.list <- list()
> ex.list[[1]] <- integer(0)
> ex.list[[2]] <- c(1,2,3)
> ex.list
[[1]]
integer(0)
[[2]]
[1] 1 2 3
> unlist(ex.list)
[1] 1 2 3
Thanks.
A way of doing it is to use function is.na<-.
is.na(ex.list) <- lengths(ex.list) == 0
ex.list
#[[1]]
#[1] NA
#
#[[2]]
#[1] 1 2 3
Then you will have a NA where the list had a length of 0.
unlist(ex.list)
#[1] NA 1 2 3
We can do an assignment based on the length of the list element i.e. if it is equal to 0, assign as NA
ex.list[lengths(ex.list)==0] <- NA
ex.list
#[[1]]
#[1] NA
#[[2]]
#[1] 1 2 3
You could also try the one-liner
unlist(lapply(ex.list, function (x) ifelse(length (x) > 0, x, NA)))
Supposed I have the following list:
x <- list(rbind(c(1,1,1,0),c(1,0,1,0), c(1,0,0,0)), c(1,1,0,1), c(1,2,3,4))
I know how to use unlist(lapply(x, "[[", 4)), but it works only when they are vectors inside the list.
If I want to extract the last column of each list, how can I do this ?
The return should be c(0, 1, 4).
Thank you
The second and third list elements are just vectors. Also, your description of extracting the last column and expected result is confusing. If you want to extract the last element.
sapply(x, function(.x) tail(c(.x),1))
#[1] 0 1 4
Or you could convert the vector elements to matrix and then extract the columns.
x1 <- lapply(x, function(.x) if(is.vector(.x)) t(.x) else (.x))
x2 <- lapply(x1, `[`,,4)
x2
#[[1]]
#[1] 0 0 0
#[[2]]
#[1] 1
#[[3]]
#[1] 4
unique(unlist(x2))
#[1] 0 1 4
Also, your code is only extracting the elements at specific positions and not the columns. For example:
z <- list(matrix(c(1:6), ncol=3), matrix(c(1:12), ncol=4))
lapply(z, `[[`, 3) #extracts the third element and not the third column
#[[1]]
#[1] 3
#[[2]]
#[1] 3
whereas,
lapply(z, `[`, ,3)
#[[1]]
#[1] 5 6
#[[2]]
#[1] 7 8 9
I would use
unlist(lapply(x, function(y) if(is.vector(y)) y[length(y)] else unique(y[,ncol(y)])))
#[1] 0 1 4