Tom
Tom

Reputation: 127

How to use for loops with nested lists?

Here is an example (with dummy numbers) of a nested list with three levels:

mylist <- list("A" = list("A1" = list("1", "2", "3"),
                          "A2" = list("10", "20", "30")),                          
               "B" = list("B1" = list("11", "22", "33"),
                          "B2" = list("110", "220", "330")))

I would like to extract the last element of each sublist (at the lower level) to a dataframe, to wrangle more easily with the data and do further calculations. The output would look like something like that:

> mylist
  First_level   Second_level   Last_value
> A             A1            3
> A             A2            30
> B             B1            33
> B             B2            330

Here is a potential dataframe structure to receive the output.

df <- data.frame(First_level = character(),
                 Second_level = character(),
                 Last_value = integer())

I have tried a for loop:

for (i in length(mylist)){
  for (j in length(mylist[[i]])){
    df$last_element <- tail(mylist[[i]][[j]], 1)
  }
}
df

But I must be too ignorant about nested lists to write correctly a double for loop to achieve this... Could you help?

Upvotes: 3

Views: 850

Answers (2)

det
det

Reputation: 5232

With tidyverse packages:

library(tidyverse)

map(mylist, ~map(.x, tail, 1)) %>% 
  unlist() %>% 
  as.list() %>% 
  as_tibble() %>%
  pivot_longer(cols = everything()) %>% 
  separate(col = "name", sep = "\\.", into = c("first_level", "second_level"))

# A tibble: 4 x 3
  first_level second_level value
  <chr>       <chr>        <chr>
1 A           A1           3    
2 A           A2           30   
3 B           B1           33   
4 B           B2           330 

Upvotes: 2

akrun
akrun

Reputation: 887118

We could use rrapply with melt

library(rrapply)
library(dplyr)
rrapply(mylist, how = 'melt') %>% 
    group_by(First_level = L1, Second_level = L2) %>% 
    summarise(Last_value = last(value), .groups = 'drop')
# A tibble: 4 x 3
# Groups:   First_level [2]
#  First_level Second_level Last_value
#  <chr>       <chr>        <chr>     
#1 A           A1           3         
#2 A           A2           30        
#3 B           B1           33        
#4 B           B2           330     

In the OP's loop, it is looping over a single value i.e. the length instead it would be 1:length or seq_along

out <- list()
for(i in seq_along(mylist)) {
    for(j in seq_along(mylist[[i]])) {
        out <- c(out, tail(mylist[[i]][[j]], 1))
    }
 }

Upvotes: 3

Related Questions