Debjyoti
Debjyoti

Reputation: 177

Obtain positions of multiple characters simultaneously from a list in R

My data structure is as follows:

m 
[[1]]
[[1]][[1]]
[1] "g" "g" "h" "k" "k" "k" "l"
[[2]]
[[2]][[1]]
[1] "g" "h" "k" "k" "k" "l" "g"
[[3]]
[[3]][[1]]
[1] "g" "h" "h" "h" "k" "l" "h"

I want to find positions of each unique characters simultaneously. Individually I can obtain positions of each character using the following code:

t<-list()
for (i in 1:length(m)){
for (j in m[[i]][[1]]){
if (j=="k"){
t[[i]]<-grep(j,m[[i]][[1]],fixed=TRUE)}}}

The result I obtain is as follows:

t
[[1]]
[1] 4 5 6
[[2]]
[1] 3 4 5
[[3]]
[1] 5

There are 4 unique characters in list m and I will get 4 lists with positions of unique characters using my code but I have to manually enter each character into the loop. I need a single code which will calculate positions for all the unique characters simultaneously.

Upvotes: 0

Views: 46

Answers (2)

Ronak Shah
Ronak Shah

Reputation: 389095

We can use a double loop with lapply where we check position using which for each unique value in m

lst <- lapply(unique(unlist(m)), function(x) 
              lapply(m, function(y) which(x == y[[1]])))
lst

#[[1]]
#[[1]][[1]]
#[1] 1 2

#[[1]][[2]]
#[1] 1 7

#[[1]][[3]]
#[1] 1


#[[2]]
#[[2]][[1]]
#[1] 3

#[[2]][[2]]
#[1] 2

#[[2]][[3]]
#[1] 2 3 4 7
......

To identify which values represent which character we can name the list

names(lst) <- unique(unlist(m))

lst
#$g
#$g[[1]]
#[1] 1 2

#$g[[2]]
#[1] 1 7

#$g[[3]]
#[1] 1

...

Upvotes: 0

Roland
Roland

Reputation: 132804

The vectors in your list seem all to be of equal length (if not this could be adjusted by making them equal length). I would first restructure the data:

m <- list(list(c("g", "g", "h", "k", "k", "k", "l")),
          list(c("g", "h", "k", "k", "k", "l", "g")))

m <- do.call(rbind, lapply(m, "[[", 1))
#     [,1] [,2] [,3] [,4] [,5] [,6] [,7]
#[1,] "g"  "g"  "h"  "k"  "k"  "k"  "l" 
#[2,] "g"  "h"  "k"  "k"  "k"  "l"  "g" 

Then you can use outer to make all comparisons at once:

res <- which(outer(m, unique(c(m)), "=="), arr.ind = TRUE)
res <- as.data.frame(res)
res$dim3 <- factor(res$dim3, labels = unique(c(m)))
names(res) <- c("list_element", "vector_element", "letter")

#check
res[res$letter == "k" & res$list_element == 1, "vector_element"]
[1] 4 5 6

This solution won't work well if your data is huge.

Upvotes: 1

Related Questions