Appending vector values to sublists - r

Let's assume we have a list with three sublists: list1 <- [[1,2],[4,5],[7,8]]
and a vector: vector1 <- c(3,6,9)
Is there a way in R, without using loops, to append vector's values to the list, so we could get the result list2 = [[1,2,3],[4,5,6],[7,8,9]]
?
Thanks for all comments

Use Map
Map(c, list1, vector1)
#[[1]]
#[1] 1 2 3
#[[2]]
#[1] 4 5 6
#[[3]]
#[1] 7 8 9
Or lapply
lapply(seq_along(list1), function(x) c(list1[[x]], vector1[[x]]))
The equivalent purrr variants can be
purrr::map2(list1, vector1, c)
purrr::map(seq_along(list1), ~c(list1[[.]], vector1[[.]]))
data
list1 <- list(c(1,2),c(4,5),c(7,8))
vector1 <- c(3,6,9)

Related

Get indexes of unique values in a vector

I have a vector like this.
filenames <- c("kisyu2_mst.csv", "kisyu3_mst.csv", "kisyu2_mst.csv",
"kisyu3_mst.csv", "kisyu3_mst.csv")
I need to get indices from filenames vector for each unique value.output look like this
for "kisyu2_mst.csv" indices vector c(1,3)
for "kisyu3_mst.csv" indices vector c(2,4,5)
Finally, I need to insert it to a list like this:
final <- list("kisyu2_mst.csv" = c(1,3), "kisyu3_mst.csv"=c(2,4,5))
How to get the indices of unique value from the vector?
We can use split
split(seq_along(filenames), filenames)
#$kisyu2_mst.csv
#[1] 1 3
#$kisyu3_mst.csv
#[1] 2 4 5
We could try which:
sapply(unique(filenames), function(i) which(filenames %in% i))
# $kisyu2_mst.csv
# [1] 1 3
#
# $kisyu3_mst.csv
# [1] 2 4 5
We can use tapply
tapply(seq_along(filenames), filenames, FUN = I)
#$kisyu2_mst.csv
#[1] 1 3
#$kisyu3_mst.csv
#[1] 2 4 5

How can I remove elements by columns number from a list?

I've like to remove elements in a list, if the number of elements are smaller than 3.
For this I try:
#Create a list
my_list <- list(a = c(3,5,6), b = c(3,1,0), c = 4, d = NA)
my_list
$a
[1] 3 5 6
$b
[1] 3 1 0
$c
[1] 4
$d
[1] NA
# Thant I create a function for remove the elements by my condition:
delete.F <- function(x.list){
x.list[unlist(lapply(x.list, function(x) ncol(x)) < 3)]}
delete.F(my_list)
And I have as output:
Error in unlist(lapply(x.list, function(x) ncol(x)) < 3) :
(list) object cannot be coerced to type 'double'
Any ideas, please?
An option is to create a logical expression with lengths and use that for subsetting the list
my_list[lengths(my_list) >=3]
#$a
#[1] 3 5 6
#$b
#[1] 3 1 0
Note that in the example, it is a list of vectors and not a list of data.frame. the ncol/nrow is when there is a dim attribute - matrix checks TRUE for that, as do data.frame
If we want to somehow use lapply (based on some constraints), create the logic with length
unlist(lapply(my_list, function(x) if(length(x) >=3 ) x))
If we need to create the index with lapply, use length (but it would be slower than lengths)
my_list[unlist(lapply(my_list, length)) >= 3]
Here are few more options. Using Filter in base R
Filter(function(x) length(x) >=3, my_list)
#$a
#[1] 3 5 6
#$b
#[1] 3 1 0
Or using purrr's keep and discard
purrr::keep(my_list, ~length(.) >= 3)
purrr::discard(my_list, ~length(.) < 3)

Count if a particular element is within a given range?

I have a vector made up of lists of length 10.
I have two other vectors storing their lower and upper quantiles.
Is there a way to extract the data between the quantile for each list of 10?
Basically I am looking to see how many of these have a specific number.
sims is the vector with the data
so far I have tried to use the %in% (note- sims is the vector with lists))
for (i in 1:100){
a <- 80.0 %in% sims[[i]]
}
I was going to count how many of these are true and then count them however, this only returns false and also doesn't guarantee if it is in the range.
Is there an easier way than sorting each list by extracting relevant data then checking if it is has the value?
Since you don't provide a sample dataset here is a reproducible example based on some sample data I generate
set.seed(2018)
lst <- replicate(4, sample(10), simplify = FALSE)
qrt <- lapply(lst, quantile, probs = c(0.25, 0.75))
Here I've generated the 25% and 75% quantiles for every vector in list; the result is a list with as many elements as list.
We can now use Map to select only those entries from the list elements that fall within the quantile range
Map(function(x, y) x[x >= y[1] & x <= y[2]], lst, qrt)
#[[1]]
#[1] 4 5 7 6
#
#[[2]]
#[1] 4 6 5 7
#
#[[3]]
#[1] 6 5 4 7
#
#[[4]]
#[1] 4 7 6 5
To count the number of elements within the quantile range
Map(function(x, y) sum(x >= y[1] & x <= y[2]), lst, qrt)
#[[1]]
#[1] 4
#
#[[2]]
#[1] 4
#
#[[3]]
#[1] 4
#
#[[4]]
#[1] 4

Subset list of vectors with vector of positions

I have a list of vectors (mylist):
a <- c(1,2,3,4)
b <- c(5,6,7,8)
c <- c(9,10,11,12)
mylist <- list(a,b,c)
I also have a vector of positions (mypos):
mypos <- c(1,2,3)
I would like to use mypos to give the position of elements to subset each vector of mypos so that it returns:
[1] 1 6 11
I have tried using lapply like this:
lapply(mylist, "[", mypos)
but this returns elements 1, 2 and 3 of each vector:
[[1]]
[1] 1 2 3
[[2]]
[1] 5 6 7
[[3]]
[1] 9 10 11
I have also tried:
lapply(mylist, subset, mypos)
But this returns an error that the subset must be logical
We can use Map to extract the corresponding elements of 'mylist' from the index of 'mypos'
Map(`[`, mylist, mypos)
In the OP's code, the 'mypos' is repeated in each of list elements resulting in extracting all the elements from the index. Instead it could be looped on sequence
lapply(seq_along(mylist), function(x) mylist[[x]][mypos[[x]]])

Dynamically creating named list in R

I need to create named lists dynamically in R as follows.
Suppose there is an array of names.
name_arr<-c("a","b")
And that there is an array of values.
value_arr<-c(1,2,3,4,5,6)
What I want to do is something like this:
list(name_arr[1]=value_arr[1:3])
But R throws an error when I try to do this. Any suggestions as to how to get around this problem?
you can use [[...]] to assign values to keys given by strings:
my.list <- list()
my.list[[name_arr[1]]] <- value_arr[1:3]
You could use setNames. Examples:
setNames(list(value_arr[1:3]), name_arr[1])
#$a
#[1] 1 2 3
setNames(list(value_arr[1:3], value_arr[4:6]), name_arr)
#$a
#[1] 1 2 3
#
#$b
#[1] 4 5 6
Or without setNames:
mylist <- list(value_arr[1:3])
names(mylist) <- name_arr[1]
mylist
#$a
#[1] 1 2 3
mylist <- list(value_arr[1:3], value_arr[4:6])
names(mylist) <- name_arr
mylist
#$a
#[1] 1 2 3
#
#$b
#[1] 4 5 6
Your code will throw a error. Because in list(A = B), A must be a name instead of an object.
You could convert a object to a name by function eval. Here is the example.
eval(parse(text = sprintf('list(%s = value_arr[1:3])',name_arr[1])))

Resources