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

前端 未结 5 472
星月不相逢
星月不相逢 2020-11-22 03:43

The R language has a nifty feature for defining functions that can take a variable number of arguments. For example, the function data.frame takes any number of

5条回答
  •  挽巷
    挽巷 (楼主)
    2020-11-22 04:28

    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(...).

提交回复
热议问题