Are there alternatives for magrittr::freduce that can accept additional parameters?

Viewed 61

A useful function that I've found in the Magrittr package is freduce: freduce(value, function_list) where the value is piped from each function to the next, sequentially. The problem is that some of my functions take other parameters (in my case a single parameter that will be the same for each function). Does anyone know of a similar function that does what magrittr::freduce . I'm going to try to implement this for myself using Purrr functions, or and if that fails just loops or recursion. I'm curious if anyone has experience or a simple solution to this problem of wanting to use additional parameters in with freduce.

2 Answers

I'm not sure about any alternative, but the source code of magrittr::freduce() is quite simple, see GitHub. It is using base R's Recall(). So you can use it to create your own function like this (e.g. with additional parameter na.rm):

freduce2 <- function(value, function_list, na.rm = TRUE)
{
  if (length(function_list) == 1L)
    function_list[[1L]](value, na.rm = na.rm)
  else 
    Recall(function_list[[1L]](value, na.rm = na.rm), function_list[-1L], na.rm = na.rm)
}

freduce2(c(1, 3, NA), list(mean, median), na.rm = TRUE)
#> [1] 2

Created on 2020-07-17 by the reprex package (v0.3.0)

I'm not sure if this is what you're looking for, but you can easily write a function that takes arguments as if you were piping them:

freduce2 <- function(data, ...)
{
  calls <- as.list(match.call())[-1][-1]
  
  for(i in seq_along(calls))
  {
     data <- eval(as.call(list(bquote(`%>%`), data, calls[[i]])), envir = parent.frame())
  }
  
  return(data)
}

It works like this:

freduce2("hello", toupper, nchar, sum)
#> [1] 5

freduce2("hello", paste("world"), toupper)
#> [1] "HELLO WORLD"

freduce2("hello", paste("world"), toupper, rep(3), strsplit(""))
#> [[1]]
#>  [1] "H" "E" "L" "L" "O" " " "W" "O" "R" "L" "D"
#> 
#> [[2]]
#>  [1] "H" "E" "L" "L" "O" " " "W" "O" "R" "L" "D"
#> 
#> [[3]]
#>  [1] "H" "E" "L" "L" "O" " " "W" "O" "R" "L" "D"

It would also be possible to pass the functions as a list, but their parameters would also need to be put into separate lists, and that seems like a lot more work for interactive use.

Related