1

Apologies if this has already been answered somewhere, but I checked all the pages I could find and can’t find a solution to this specific problem.

I want to use an apply function to select elements from lists nested within a list. The element I want to select from the sub-lists vary based on a arguments contained in a separate list. Here is some example code to illustrate what I am trying to do:

# Set seed for replicable results
set.seed(123)

# Create list of lists populated with randomly generated numbers
list1 <- list()
for (i in 1:10) {
  list1[[i]] <- as.list(sample.int(20, 10))
}

# Create second randomly generated list
list2 <- as.list(sample.int(10, 10))

# For loop with uses values from list 2 to call specific elements from sub-lists within list1
for (i in 1:10){
  print(list1[[i]][[list2[[i]]]])
}

####################################################################################

[1] 4
[1] 8
[1] 5
[1] 8
[1] 15
[1] 17
[1] 12
[1] 15
[1] 3
[1] 15

As you can see, I can use a for loop to successfully to select elements from the sub-lists nested within list1 using values from list2 in combination with the iterating value i. Solutions offered to questions like this (R apply function with multiple parameters), suggest that I should be able to achieve this same result using the mapply function. However, when I try to do this I get the following error:

# Attempt to replicate output using mapply
mapply(function(x,y,z) x <- x[[z]][[y[[z]]]], x=list1, y=list2, z=1:10 )

####################################################################################

Error in x[[z]][[y[[z]]]] : subscript out of bounds

My questions are:

  1. How can my code can be altered to achieve the desired outcome?

  2. What is causing this error? I have had similar problems with mapply in the past, when I have tried to input one or more lists alongside a vector, and have never been able to work out why it sometimes fails.

Many thanks in advance!

Misc584
  • 357
  • 3
  • 16

2 Answers2

2

Try this. It is better to use a function to catch the desired values. The reason why you got an error is because functions works different when using indexing. It is better to set the function directly inside the *apply() sketch to reach the desired outcome. Here the code:

#Code
unlist(mapply(function(x,y) x[y],x=list1,y=list2))

Output:

[1]  4  8  5  8 15 17 12 15  3 15

Or if you want the output in a list:

#Code 2
List <- mapply(function(x,y) x[y],x=list1,y=list2)

Output:

List
[[1]]
[1] 4

[[2]]
[1] 8

[[3]]
[1] 5

[[4]]
[1] 8

[[5]]
[1] 15

[[6]]
[1] 17

[[7]]
[1] 12

[[8]]
[1] 15

[[9]]
[1] 3

[[10]]
[1] 15

Another simplified options can be (Many thanks and all credit to @27ϕ9):

#Code3
mapply(`[[`, list1, list2)

Output:

[1]  4  8  5  8 15 17 12 15  3 15

Or:

#Code4
mapply(`[`, list1, list2)

Output:

[[1]]
[1] 4

[[2]]
[1] 8

[[3]]
[1] 5

[[4]]
[1] 8

[[5]]
[1] 15

[[6]]
[1] 17

[[7]]
[1] 12

[[8]]
[1] 15

[[9]]
[1] 3

[[10]]
[1] 15
Duck
  • 39,058
  • 13
  • 42
  • 84
  • @27ϕ9 I will add to the post with credits to you! Just a moment! – Duck Oct 14 '20 at 12:25
  • 1
    Thanks so much for the swift @Duck and @27ϕ9! If I'm honest, I'm not entirely sure how this solution works, but that's great because hopefully I can use it to learn more about the structure of lists and the apply functions. Thanks again :) – Misc584 Oct 14 '20 at 12:37
1

If you look at your for loop there is only one variable which is changing i.e i. So in this case you can use lapply or even sapply since you are getting a single number back.

sapply(1:10, function(i) list1[[i]][[list2[[i]]]])
#[1]  4  8  5  8 15 17 12 15  3 15
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
  • Many thanks @Ronak Shah! That's a solution hadn't thought of, but it's very useful. I will definitely use it in future :) – Misc584 Oct 14 '20 at 12:35