Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R base pipe into `do.call`

Tags:

r

Suppose I have a list (myList) consisting of some data.frame objects and I want to collapse all of the elements within the list into one data.frame structure using rbind in a do.call method:

set.seed(123)
myList <- list(
    a = data.frame(
        h1 = rnorm(5),
        h2 = rnorm(5)
    ),
    b = data.frame(
        h1 = rnorm(5),
        h2 = rnorm(5)
    )
)

Using magrittr's pipe operator (%>%), you could do something like this where the second argument in do.call (args) is the lhs expression as denoted by a .:

myList %>% do.call("rbind", .)

But using the new base pipe (|>) leads to errors performing the same operation:

myList |> do.call("rbind", .)
#> Error in do.call(myList, "rbind", .) : 
#>  second argument must be a list

What is the proper way of piping this (and other similar operations) into R's new base pipe operator where the lhs expression isn't necessarily the first argument in a method?

like image 889
btmonier Avatar asked Nov 16 '25 13:11

btmonier


1 Answers

1) named argument |> always inserts into the first argument and does not support dot but this works:

myList |> do.call(what = "rbind")

2) anonymous function call Although a bit verbose this also works:

myList |> (\(args) do.call("rbind", args))()

2a) named function or define Do.call like do.call but with the first two arguments swapped:

Do.call <- \(args, what, ...) do.call(what, args, ...)
myList |> Do.call("rbind")

2b) or define a function which accepts the second argument, the function and the first and remaining arguments.

Swap <- \(x, fun, y, ...) fun(y, x, ...)
myList |> Swap(do.call, "rbind")

3) myList structure known If you knew that myList had exactly two components and they were named a and b then this would also work:

myList |> with(rbind(a, b))

4) Pipe Alternatives Of course there is nothing to prevent continued use of the magrittr pipe. Also the Bizarro pipe, which is not really a pipe but looks like one, and only requires base R can be used:

myList ->.;
  do.call("rbind", .)

5) rbind Alternatives Instead of using rbind use bind_rows from dplyr or rbindlist from data.table:

library(dplyr)
myList |> bind_rows()

library(data.table)
myList |> rbindlist()

6) do.call Alternatives Use reduce from purrr instead of do.call which, at least in this example, works.

library(purrr)
myList |> reduce(rbind)

Update

Since this was posted R added _ like this. It must be used with a named argument.

myList |> do.call("rbind", args = _)
like image 96
G. Grothendieck Avatar answered Nov 18 '25 04:11

G. Grothendieck



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!