编写自己的函数时如何使用R的省略号功能?
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.frame
函数定义中的相关行是 object <- 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)
编辑
似乎有两种可能的方法可以做到这一点。它们是 as.list(substitute(list(...)))[-1L]
和 list(...)
。然而,这两者所做的事情并不完全相同。 (有关差异,请参阅答案中的示例。)谁能告诉我它们之间的实际差异是什么,以及我应该使用哪一个?
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 arguments, and each argument becomes the data for a column in the resulting data table. Example usage:
> 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
The function's signature includes an ellipsis, like this:
function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE,
stringsAsFactors = default.stringsAsFactors())
{
[FUNCTION DEFINITION HERE]
}
I would like to write a function that does something similar, taking multiple values and consolidating them into a single return value (as well as doing some other processing). In order to do this, I need to figure out how to "unpack" the ...
from the function's arguments within the function. I don't know how to do this. The relevant line in the function definition of data.frame
is object <- as.list(substitute(list(...)))[-1L]
, which I can't make any sense of.
So how can I convert the ellipsis from the function's signature into, for example, a list?
To be more specific, how can I write get_list_from_ellipsis
in the code below?
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)
Edit
It seems there are two possible ways to do this. They are as.list(substitute(list(...)))[-1L]
and list(...)
. However, these two do not do exactly the same thing. (For differences, see examples in the answers.) Can anyone tell me what the practical difference between them is, and which one I should use?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我阅读了答案和评论,发现几乎没有提到什么:
data.frame
使用list(...)
版本。代码片段:object
用于对列名进行一些魔法,但x
用于创建最终的要使用未评估的
...
参数,请查看使用match.call
的write.csv
代码。正如您在德克的评论结果中所写的那样,答案不是列表的列表。是一个长度为4的列表,其中元素是
language
类型。第一个对象是symbol
-list
,第二个对象是表达式1:10
等等。这解释了为什么需要[-1L]
:它从...
中提供的参数中删除了预期的symbol
(因为它始终是一个列表) .正如德克所说,
substitute
返回“解析树未计算的表达式”。当您调用
my_ellipsis_function(a=1:10,b=11:20,c=21:30)
时,...
“创建”参数列表:< code>list(a=1:10,b=11:20,c=21:30) 和substitute
使其成为一个包含四个元素的列表:第一个元素没有名称,这是 Dirk 答案中的
[[1]]
。我使用以下方法实现了此结果:如上所述,我们可以使用
str
来检查函数中有哪些对象。没关系。让我们看看
替代
版本:这不是我们需要的。您将需要额外的技巧来处理此类对象(如
write.csv
中所示)。如果您想使用
...
那么您应该像 Shane 答案中那样使用它,通过list(...)
。I read answers and comments and I see that few things weren't mentioned:
data.frame
useslist(...)
version. Fragment of the code:object
is used to do some magic with column names, butx
is used to create finaldata.frame
.For use of unevaluated
...
argument look atwrite.csv
code wherematch.call
is used.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 asymbol
-list
, second is expression1:10
and so on. That explain why[-1L]
is needed: it removes expectedsymbol
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)
andsubstitute
make it a list of four elements:First element doesn't have a name and this is
[[1]]
in Dirk answer. I achieve this results using:As above we can use
str
to check what objects are in a function.It's ok. Lets see
substitute
version: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, bylist(...)
.您可以使用
list()
将省略号转换为列表,然后对其执行操作:因此您的
get_list_from_ellipsis
函数只不过是list
。一个有效的用例是您想要传入未知数量的对象进行操作的情况(如您的
c()
或data.frame()
)。然而,当您提前知道每个参数时,使用...
并不是一个好主意,因为它会增加参数字符串的歧义性和进一步的复杂性(并使函数签名对于任何其他参数都不清楚)用户)。对于函数用户来说,参数列表是一个重要的文档。否则,当您想要将参数传递给子函数而不将它们全部暴露在您自己的函数参数中时,它也很有用。这可以在函数文档中注明。
You can convert the ellipsis into a list with
list()
, and then perform your operations on it:So your
get_list_from_ellipsis
function is nothing more thanlist
.A valid use case for this is in cases where you want to pass in an unknown number of objects for operation (as in your example of
c()
ordata.frame()
). It's not a good idea to use the...
when you know each parameter in advance, however, as it adds some ambiguity and further complication to the argument string (and makes the function signature unclear to any other user). The argument list is an important piece of documentation for function users.Otherwise, it is also useful for cases when you want to pass through parameters to a subfunction without exposing them all in your own function arguments. This can be noted in the function documentation.
只是补充一下 Shane 和 Dirk 的回复:
与
目前的情况进行比较很有趣,两个版本似乎都适合您在
my_ellipsis_function
中的目的,尽管第一个版本显然更简单。Just to add to Shane and Dirk's responses: it is interesting to compare
with
As it stands, either version appears suitable for your purposes in
my_ellipsis_function
, though the first is clearly simpler.你已经给出了一半答案了。考虑
一下,这从调用中获取了两个参数
a
和b
并将其转换为列表。这不是你要求的吗?You gave half the answer already. Consider
So this took two arguments
a
andb
from the call and converted it to a list. Wasn't that what you asked for?这按预期工作。
以下是一个交互式会话:
相同,但有默认参数:
如您所见,如果在特定情况下默认值不是您想要的,您可以使用它向函数内的函数传递“额外”参数。
This works as expected.
The following is an interactive session:
Same, except with a default argument:
As you can see, you can use this to pass 'extra' arguments to a function within your function if the defaults are not what you want in a particular case.