202

R 言語には、可変数の引数を取ることができる関数を定義するための便利な機能があります。たとえば、関数data.frameは任意の数の引数を取り、各引数は結果のデータ テーブルの列のデータになります。使用例:

> data.frame(letters=c("a", "b", "c"), numbers=c(1,2,3), notes=c("do", "re", "mi"))
  letters numbers notes
1       a       1    do
2       b       2    re
3       c       3    mi

関数のシグネチャには、次のように省略記号が含まれます。

function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE, 
    stringsAsFactors = default.stringsAsFactors()) 
{
    [FUNCTION DEFINITION HERE]
}

複数の値を取り、それらを単一の戻り値に統合する(および他の処理を行う)、同様のことを行う関数を作成したいと思います。これを行うには...、関数内で関数の引数から を「アンパック」する方法を理解する必要があります。これを行う方法がわかりません。の関数定義の関連する行data.frameobject <- as.list(substitute(list(...)))[-1L]、私には意味がわかりません。

では、関数のシグネチャの省略記号をたとえばリストに変換するにはどうすればよいでしょうか?

より具体的にget_list_from_ellipsisは、以下のコードにどのように記述すればよいでしょうか?

my_ellipsis_function(...) {
    input_list <- get_list_from_ellipsis(...)
    output_list <- lapply(X=input_list, FUN=do_something_interesting)
    return(output_list)
}

my_ellipsis_function(a=1:10,b=11:20,c=21:30)

編集

これを行うには2つの方法があるようです。as.list(substitute(list(...)))[-1L]とですlist(...)。ただし、これら 2 つはまったく同じことを行うわけではありません。(違いについては、回答の例を参照してください。)それらの実際の違いは何か、どちらを使用すべきか教えてもらえますか?

4

5 に答える 5

119

回答とコメントを読みましたが、言及されていないことがいくつかあります。

  1. data.frameバージョンを使用しlist(...)ます。コードのフラグメント:

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

    object列名を使って魔法をかけるxために使用されますが、finalを作成するために使用されますdata.frame。未評価の引数
    の使用については、使用されているコードを参照してください。...write.csvmatch.call

  2. あなたがコメントで書くとき、Dirkの結果はリストのリストではありません。要素がlanguageタイプである長さ4のリストです。最初のオブジェクトはsymbol- list、2番目は式1:10などです。それが必要な理由を説明しています:それはで提供された引数から[-1L]expectedを削除します(それは常にリストであるため)。 Dirkが述べているように、「解析ツリーの未評価の式」を返します。次に 呼び出すと、引数のリストが「作成」され、4つの要素のリストになります。symbol...
    substitute
    my_ellipsis_function(a=1:10,b=11:20,c=21:30)...list(a=1:10,b=11:20,c=21:30)substitute

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

    最初の要素には名前がなく、これは[[1]]Dirkの回答にあります。私は以下を使用してこの結果を達成します:

    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. 上記のようstrに、関数内のオブジェクトを確認するために使用できます。

    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 
    

    大丈夫です。substituteバージョンを見てみましょう:

       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 
    

    私たちが必要としていたものではありません。これらの種類のオブジェクトを処理するには、追加のトリックが必要になります(のようにwrite.csv)。

使用したい場合は...、シェーンの回答のように使用する必要がありますlist(...)

于 2010-06-21T08:50:26.133 に答える
40

を使用して省略記号をリストに変換し、list()それに対して操作を実行できます。

> test.func <- function(...) { lapply(list(...), class) }
> test.func(a="b", b=1)
$a
[1] "character"

$b
[1] "numeric"

したがって、あなたのget_list_from_ellipsis機能はlist.

これの有効な使用例は、操作のために不明な数のオブジェクトを渡したい場合です(c()またはの例のようにdata.frame())。ただし、事前に各パラメーターがわかっている場合にを使用することはお勧めできません。...これは、あいまいさが増し、引数文字列がさらに複雑になるためです (また、関数のシグネチャが他のユーザーにとって不明確になります)。引数リストは、関数のユーザーにとって重要なドキュメントです。

それ以外の場合は、独自の関数引数ですべてを公開せずにパラメーターをサブ関数に渡したい場合にも役立ちます。これは、関数のドキュメントに記載されています。

于 2010-06-16T21:45:32.673 に答える
34

シェーンとダークの回答に追加するだけです。比較するのは興味深いことです。

get_list_from_ellipsis1 <- function(...)
{
  list(...)
}
get_list_from_ellipsis1(a = 1:10, b = 2:20) # returns a list of integer vectors

$a
 [1]  1  2  3  4  5  6  7  8  9 10

$b
 [1]  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20

get_list_from_ellipsis2 <- function(...)
{
  as.list(substitute(list(...)))[-1L]
}
get_list_from_ellipsis2(a = 1:10, b = 2:20) # returns a list of calls

$a
1:10

$b
2:20

現状では、どちらのバージョンもでの目的に適しているように見えますmy_ellipsis_functionが、最初のバージョンの方が明らかに単純です。

于 2010-06-17T15:37:19.797 に答える
18

あなたはすでに半分答えました。検討

R> my_ellipsis_function <- function(...) {
+   input_list <- as.list(substitute(list(...)))
+ }
R> print(my_ellipsis_function(a=1:10, b=2:20))
[[1]]
list

$a
1:10

$b
11:20

R> 

したがって、これは呼び出しからaと の 2 つの引数を取りb、それをリストに変換しました。それはあなたが求めたものではありませんでしたか?

于 2010-06-16T21:45:09.617 に答える