How to Use R'S Ellipsis Feature When Writing Your Own Function

How to use R's ellipsis feature when writing your own function?

I read answers and comments and I see that few things weren't mentioned:

  1. data.frame uses list(...) version. Fragment of the code:

    object <- as.list(substitute(list(...)))[-1L]
    mrn <- is.null(row.names)
    x <- list(...)

    object is used to do some magic with column names, but x is used to create final data.frame.

    For use of unevaluated ... argument look at write.csv code where match.call is used.

  2. As you write in comment result in Dirk answer is not a list of lists. Is a list of length 4, which elements are language type. First object is a symbol - list, second is expression 1:10 and so on. That explain why [-1L] is needed: it removes expected symbol from provided arguments in ... (cause it is always a list).

    As Dirk states substitute returns "parse tree the unevaluated expression".

    When you call my_ellipsis_function(a=1:10,b=11:20,c=21:30) then ... "creates" a list of arguments: list(a=1:10,b=11:20,c=21:30) and substitute make it a list of four elements:

    List of 4
    $ : symbol list
    $ a: language 1:10
    $ b: language 11:20
    $ c: language 21:30

    First element doesn't have a name and this is [[1]] in Dirk answer. I achieve this results using:

    my_ellipsis_function <- function(...) {
    input_list <- as.list(substitute(list(...)))
    str(input_list)
    NULL
    }
    my_ellipsis_function(a=1:10,b=11:20,c=21:30)
  3. As above we can use str to check what objects are in a function.

    my_ellipsis_function <- function(...) {
    input_list <- list(...)
    output_list <- lapply(X=input_list, function(x) {str(x);summary(x)})
    return(output_list)
    }
    my_ellipsis_function(a=1:10,b=11:20,c=21:30)
    int [1:10] 1 2 3 4 5 6 7 8 9 10
    int [1:10] 11 12 13 14 15 16 17 18 19 20
    int [1:10] 21 22 23 24 25 26 27 28 29 30
    $a
    Min. 1st Qu. Median Mean 3rd Qu. Max.
    1.00 3.25 5.50 5.50 7.75 10.00
    $b
    Min. 1st Qu. Median Mean 3rd Qu. Max.
    11.0 13.2 15.5 15.5 17.8 20.0
    $c
    Min. 1st Qu. Median Mean 3rd Qu. Max.
    21.0 23.2 25.5 25.5 27.8 30.0

    It's ok. Lets see substitute version:

       my_ellipsis_function <- function(...) {
    input_list <- as.list(substitute(list(...)))
    output_list <- lapply(X=input_list, function(x) {str(x);summary(x)})
    return(output_list)
    }
    my_ellipsis_function(a=1:10,b=11:20,c=21:30)
    symbol list
    language 1:10
    language 11:20
    language 21:30
    [[1]]
    Length Class Mode
    1 name name
    $a
    Length Class Mode
    3 call call
    $b
    Length Class Mode
    3 call call
    $c
    Length Class Mode
    3 call call

    Isn't what we needed. You will need additional tricks to deal with these kind of objects (as in write.csv).

If you want use ... then you should use it as in Shane answer, by list(...).

What does passing an ellipsis (...) as an argument mean in R?

The typical use of ... argument is when a function say f internally calls a function g and uses ... to pass arguments to g without explicitly listing all those arguments as its own formal arguments. One may want to do this, for example, when g has a lot of optional arguments that may or may not be needed by the user in the function f. Then instead of adding all those optional arguments to f and increasing complexity, one may simply use ....

What it means, as you asked, is the function f will simply ignore these and pass them on to g. The interesting thing is that ... may even have arguments that g does not want and it will ignore them too, for say h if it needed to use ... too. But also see this so post for a detailed discussion.

For example consider:

f <- function (x, y, ...) {
# do something with x
# do something with y
g(...) # g will use what it needs
h(...) # h will use that it needs
# do more stuff and exit
}

Also, see here in the intro-R manual for an example using par.

Also, this post shows how to unpack the ... if one was writing a function that made use of it.

How do I save the contents of ellipsis in R to be used in deeply nested function calls?

Change the first line to this:

load.samples <- function(..., path = ".") {

The trick is that ... should come after the regular parameters, but before the named parameters.

R: Lexical Scoping issue when creating a function with ellipsis argument

You can use quosures from rlang to capture the arguments in ... then unquote splice them into a select call:

library(tidyverse)
library(rlang)

qft <- function(data, ...){
args <- enquos(...)
vars <- select(data, !!!args)
ft <- data.frame(table(vars))
ft[ft$Freq != 0, ]
}

qft(mtcars, cyl, gear)
# cyl gear Freq
#1 4 3 1
#2 6 3 2
#3 8 3 12
#4 4 4 8
#5 6 4 4
#7 4 5 2
#8 6 5 1
#9 8 5 2

R: Using ellipsis with a function that takes a arbitrary number of arguments

You don't need to write your own function. You can do this with paste.

paste(1:3,collapse=",")
# [1] "1,2,3"

How to see if ... ellipses in R contains a certain argument?

We can capture the ... in a list and convert the whole elements to a key/value pair. Then, extract the elements based on the name. If we are not passing that particular named element, it will return NULL. We make use of this behavior of NULL to concatenate with the default value of 10 in maxRes and select the first element ([1]) so that if it is NULL, the default 10 is selected, or else the value passed will be selected. Likewise, do this on all those objects that the OP wanted to override

top_videos <- function(...) {

nm1 <- list(...)
lst1 <- as.list(nm1)

dim <- c(lst1[["dimensions"]], "video")[1]
met <- c(lst1[["metrics"]], "views,averageViewDuration")[1]
maxRes <- c(lst1[['maxResults']], 10)[1]

#temp <- yt_request(dimensions = dim,
metrics = met, maxResults = maxRes, token = myToken)
#temp
maxRes
}

-testing

top_videos(maxResults = 20)
#[1] 20

top_videos(hello = 5)
#[1] 10

Include extra (ellipsis/dot dot dot) arguments within custom function

First of all your example seems to not be a valid one.
For me updated function works correctly.

library(dplyr)
library(tidytext)
library(janeaustenr)

count_tokens <- function(data,output,token="words", ...){
d %>%
select(txt) %>%
tidytext::unnest_tokens(output, input="txt", token = token, ...) %>%
n_distinct()
}

d <- tibble(txt = prideprejudice)

count_tokens(d, "word", to_lower = FALSE)
#> [1] 6915

count_tokens(d, "ngram", token = "ngrams", to_lower = FALSE, n = 8)
#> [1] 122189

count_tokens(d, "ngram", token = "ngrams", to_lower = FALSE, n = 5)
#> [1] 121599

count_tokens(d, "ngram", token = "ngrams", to_lower = FALSE, n = 3)
#> [1] 104664

Created on 2021-02-03 by the reprex package (v0.3.0)

R: using a list for ellipsis arguments

How about

newmean <- function(X, ...){
args <- as.list(substitute(list(...)))[-1L]
z<-list(X)
z<-c(z,args)
do.call(mean,z)
}


Related Topics



Leave a reply



Submit