Get indexes of unique values in a vector - r

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

Related

How to unwrap list with access variables? [duplicate]

I have a vector like below
tmp <- c(a=1, b=2, c=3)
a b c
1 2 3
I want to flatten this vector to get only 1, 2, 3.
I tried unlist(tmp) but it still gives me the same result.
How to achieve that efficiently?
You just want to remove the names attribute from tmp. There are a number of ways to do that.
You can unname it.
unname(tmp)
# [1] 1 2 3
Or use a very common method for removing names, by setting them to NULL.
names(tmp) <- NULL
Or strip the attributes with as.vector.
as.vector(tmp)
# [1] 1 2 3
Or re-concatenate it without the names.
c(tmp, use.names=FALSE)
# [1] 1 2 3
Or use setNames.
setNames(tmp, NULL)
# [1] 1 2 3
There is a use case that the above does not cover:
tmp <- c(1,2,3)
names(tmp) <- c("a","b","c")
In this case you need to use both:
unlist(unname(tmp))

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)

Appending vector values to sublists

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)

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