1

Task:

  • I would like to apply a function conditionally with ifelse to a specific element across all sub-lists within a named list in R.
  • I would like to store this output in a named list.
  • Additionally, how can I extract the elements in the sub-lists where the condition is met and store in a new named list?

The list is of ggplot2 plots.

Data:

library(furrr)
library(data.table)

my_list <- list(ggplot_1 = ggplot_1, ggplot_2 = ggplot_2, ggplot_3 = ggplot_3)
my_names <- names(my_list)

str(my_list)
> list of 3
>  $ggplot_1 : list of 9
>   $data :'data.frame': 20 obs. of 10 variables:
    # Other sub-list elements...
>
>  $ggplot_2 : list of 9
>   $data :'data.frame': 0 obs. of 10 variables:
    # Other sub-list elements...
>
>  $ggplot_3 : list of 9
>   $data :'data.frame': 10 obs. of 10 variables:
    # Other sub-list elements...

On its own the following works:

ifelse(nrow(my_list$ggplot_1$data) != 0, TRUE, FALSE)
> TRUE
ifelse(nrow(my_list$ggplot_2$data) != 0, TRUE, FALSE)
> FALSE

Attempt:

# I have used mapping functions from the furrr package, 
# but this approach should be similar (although sequential) for purrr::map2/base::Map.

# Start multisession parallel backend
plan(multisession, workers = 2)

# Attempt to map a function conditionally through a list
future_map2(my_list, my_names, function(.x, .y) {
            ifelse(nrow(.x$.y$data) != 0, TRUE, FALSE))
  })
Buzz B
  • 75
  • 7
  • 1
    It would be helpful if you could provide us with a reproducible [minimal working example](https://en.wikipedia.org/wiki/Minimal_working_example) that we can copy and paste to better understand the issue and test possible solutions. You can share datasets with `dput(YOUR_DATASET)` or smaller samples with `dput(head(YOUR_DATASET))`. (See [this answer](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example#5963610) for some great advice.) – ktiu Jun 08 '21 at 16:53

2 Answers2

1

You don't need map2 as the names are already in the list you want to map.
ifelse is also not necessary as > operator already returns a boolean.

library(purrr)
library(ggplot2)

my_list %>% map(~nrow(.x$data)!=0)


$ggplot_1
[1] TRUE

$ggplot_2
[1] TRUE

$ggplot_3
[1] FALSE

The above example works with purrr, and you just need to replace map by future_map to transpose it to furrr.

Waldi
  • 39,242
  • 6
  • 30
  • 78
  • thank you very much. I wish I could accept more than one answer because this in conjunction with the answer from akrun has been informative and solved my issue. – Buzz B Jun 09 '21 at 02:13
1

We can use keep to filter the list elements`

purrr::keep(my_list, ~ nrow(.x$data) > 0)

Or using base R with Filter

Filter(function(x) nrow(x$data) > 0, my_list)
akrun
  • 874,273
  • 37
  • 540
  • 662
  • thank you very much. I would like to add a title (the list item's name would suffice) to each plot to identify it (unfortunately the particular `ggplot2` plots created is via another package which does not provide the parameter to add a title). I can achieve this individually with `ggtitle()`, but how might I be able to map this? I was trying `+ ggtitle(names(.x))` after the plotting function within `map()` but this didn't display the title once all plots were displayed with `library(gridExtra)` using `do.call("grid.arrange", c(my_list_keep, ncol = 3))`. – Buzz B Jun 09 '21 at 02:08
  • 1
    @BuzzB I would use `imap` and specify `ggtitle(.y)` assuming the `list`s are named – akrun Jun 09 '21 at 15:48
  • 1
    As always thank you so much for your time, effort and exceptional wisdom @akrun. This works perfectly. – Buzz B Jun 09 '21 at 15:58