Dan
Dan

Reputation: 69

R return unique values of specific sub-lists

I would like to process information for nested lists. For example, a list has 3 1st level lists with each of those lists having 10 sub-lists. I would like to find the unique values of all 1st level lists' [[i]] sub-list.

    ## Design of list
list1 = replicate(10, list(sample(10, 5, replace = FALSE)))
list2 = replicate(10, list(sample(10, 5, replace = FALSE)))
list3 = replicate(10, list(sample(10, 5, replace = FALSE)))
myList = list(list1, list2, list3)

    ## return unique values of each list's i-th sub-list
    ## example


> k = unique(myList[[1:3]][[1]])
> k
[1] 10

This returns a single value instead of all unique values. I am trying to get all unique values though. How can I properly address specific lists within lists?

Upvotes: 1

Views: 2129

Answers (2)

cmaher
cmaher

Reputation: 5215

To get the unique elements of each list at that level, this will work:

# set seed so that "random" number generation is reproducible
set.seed(123)
# set replace to TRUE so we can see if we're getting unique elements
# when replace is FALSE, all elements are already unique :)
list1 <- replicate(10, list(sample(10, 5, replace = TRUE)))
list2 <- replicate(10, list(sample(10, 5, replace = TRUE)))
list3 <- replicate(10, list(sample(10, 5, replace = TRUE)))
myList <- list(list1, list2, list3)

# use lapply to apply anonymous function to the top levels of the list
# unlist results and then call unique to get unique values
k <- unique(unlist(lapply(myList, function(x) x[[1]])

Output:

[[1]]
[1]  3  8  5  9 10

[[2]]
[1] 1 5 8 2 6

[[3]]
[1]  6  4  5 10

The issue you were having was due to the fact that you were using double-brackets (myList[[1:3]]) in the first level of your indexing. That notation only works when indexing into a single list -- to work across multiple elements of a list, use single brackets. In this case, however, that wouldn't have gotten the job done, since myList[1:3][[1]] would first have grabbed all three top-most lists, and then the first list ([[1]]) from that, so you'd end up calling unique on a list of lists (the odds in this case being that the lists are all unique).

lapply is a useful solution here, since it runs over the first level of lists you give it, and applies the function provided to each of them individually. To make the solution above more portable, we could wrap it in a function that takes an integer as an argument, so that we can dynamically select the ith element from the lower-level lists:

get.i.elem <- function(i) {
  unique(unlist(lapply(myList, function(x) x[[i]])))
}

Upvotes: 1

Lu&#237;s Telles
Lu&#237;s Telles

Reputation: 694

Try this code and let me know if this is what you wanted...

res <- list()
for(i in 1:10){
  res[[i]] <- unique(as.vector(sapply(myList, function(x) x[[i]])))
}

Upvotes: 1

Related Questions