map over list columns and extract the first list item

Viewed 112

I have the following data which looks like:

# A tibble: 6 × 2
  `Total_ Española_Porcentaje` `Total_ Extranjero_Porcentaje`
  <list>                       <list>                        
1 <dbl [3]>                    <dbl [3]>                     
2 <dbl [3]>                    <dbl [3]>                     
3 <dbl [3]>                    <dbl [3]>                     
4 <dbl [3]>                    <dbl [3]>                     
5 <dbl [3]>                    <dbl [3]>                     
6 <dbl [3]>                    <dbl [3]> 

I am trying to map over the columns using map and extract the first dbl.

I have tried

df %>%
  map_dbl(., ~if(length(.x)) .x[1] else NA)

and

df %>%
  imap_dfc(., function(x, y) 
    tibble(!!y := map_dbl(x, ~if(length(.x)) .x[1] else NA)))

But I can't get it to work.

Data <- structure(list(`Total_ Española_Porcentaje` = list(c(5.9, 5.9, 
5.9), c(5.9, 5.9, 5.9), c(5.9, 5.9, 5.9), c(5.9, 5.9, 5.9), c(5.9, 
5.9, 5.9), c(5.9, 5.9, 5.9)), `Total_ Extranjero_Porcentaje` = list(
    c(5.9, 5.9, 5.9), c(5.9, 5.9, 5.9), c(5.9, 5.9, 5.9), c(5.9, 
    5.9, 5.9), c(5.9, 5.9, 5.9), c(5.9, 5.9, 5.9))), row.names = c(NA, 
-6L), class = c("tbl_df", "tbl", "data.frame"))
3 Answers

We can use across to loop over the list columns, then map over the elements of the list, if the length is greater than 0, select the first element or else returns NA

library(dplyr)
library(purrr)
Data %>%
      mutate(across(everything(), 
       ~ map_dbl(., ~ if(length(.x) ) first(.x) else NA)))
# A tibble: 6 x 2
  `Total_ Española_Porcentaje` `Total_ Extranjero_Porcentaje`
                         <dbl>                          <dbl>
1                          5.9                            5.9
2                          5.9                            5.9
3                          5.9                            5.9
4                          5.9                            5.9
5                          5.9                            5.9
6                          5.9                            5.9

Or as inspired from @ThomasIsCoding

map_dfr(Data, map_dbl, first)
# A tibble: 6 x 2
  `Total_ Española_Porcentaje` `Total_ Extranjero_Porcentaje`
                         <dbl>                          <dbl>
1                          5.9                            5.9
2                          5.9                            5.9
3                          5.9                            5.9
4                          5.9                            5.9
5                          5.9                            5.9
6                          5.9                            5.9

A base R trick

> Data[] <- lapply(Data, sapply, `[`, 1)
> Data
# A tibble: 6 x 2
  `Total_ Espa±ola_Porcentaje` `Total_ Extranjero_Porcentaje`
                         <dbl>                          <dbl>
1                          5.9                            5.9
2                          5.9                            5.9
3                          5.9                            5.9
4                          5.9                            5.9
5                          5.9                            5.9
6                          5.9                            5.9

Maybe we can use pluck from purrr package:

pluck() implement a generalised form of [[ that allow you to index deeply and flexibly into data structures. https://purrr.tidyverse.org/reference/pluck.html

library(purrr)
pluck(Data, 1)

Output:

 pluck(2,2)
[1] 5.9 5.9 5.9
> pluck(Data,1)
[[1]]
[1] 5.9 5.9 5.9

[[2]]
[1] 5.9 5.9 5.9

[[3]]
[1] 5.9 5.9 5.9

[[4]]
[1] 5.9 5.9 5.9

[[5]]
[1] 5.9 5.9 5.9

[[6]]
[1] 5.9 5.9 5.9
Related