是否有一种简单的方法可以在保留原始类型的列表成分的同时展平列表?有没有办法以编程方式构建不同成分类型的扁平列表?...
例如,我想为png(filename,width,height)
之类的函数创建一个简单的包装器,它将获取设备名称,文件名和选项列表。天真的方法就像是
my.wrapper <- function(dev,name,opts) { do.call(dev,c(filename=name,opts)) }
或与unlist(list(...))
类似的代码。这不起作用,因为opts
被强制转换为字符,结果调用是例如png(filename,width="500",height="500")
。
如果没有直接的方法来创建这样的异构列表,是否有一种标准的惯用方法将参数拼接到函数中而不明确命名它们(例如do.call(dev,list(filename=name,width=opts["width"])
)?
- 编辑 -
Gavin Simpson在关于构建包装函数的讨论中回答了以下两个问题。让我总结一下标题问题的答案:
可以使用c()
构建一个列表,前提是c()
的至少一个参数是一个列表。即:
> foo <- c("a","b"); bar <- 1:3
> c(foo,bar)
[1] "a" "b" "1" "2" "3"
> typeof(c(foo,bar))
[1] "character" ## note that the result is not a list and that coercion occurred
> c(list(foo),list(bar)) ## try also c(foo,list(bar))
[[1]] [1] "a" "b"
[[2]] [1] 1 2 3
> typeof(c(foo,list(bar)))
[1] "list" ## now the result is a list, so no need to coerce to same type
> c(as.list(foo),as.list(bar)) ## this creates a flattened list, as desired
[[1]] [1] "a"
[[2]] [1] "b"
[[3]] [1] 1
[[4]] [1] 2
[[5]] [1] 3
答案 0 :(得分:3)
不,因为unlist
和c
(当应用于不同类型的原子向量时)正在创建原子向量,根据定义它们必须是单一类型。 R中的列表是最通用的向量,您可以使用它,实际上"args"
的do.call
参数要求列表,并且您正在提供原子向量(通过使用c()
)。
为什么使用do.call
当你所做的就是生成一个新设备?如果您想要的是png
的包装器,它设置了一些默认设置,因此您不必在每次要使用png
设备时输入所有这些默认值,那么您就太复杂了。这样的东西就足够了:
my.png <- function(name, height = 500, width = 500, ...) {
png(filename = name, height = height, width = width, ...)
}
如果你想要一个更通用的包装器,那么就像:
my.wrapper <- function(dev, name, ...) {
dev(filename = name, ...)
}
应该足够了。您可以使用它:
my.wrapper(png, "my_png.png", height = 500, width = 200, pointsize = 12)
或
my.wrapper(pdf, "my_pdf.pdf", height = 8, width = 6, version = "1.4")
如果您想使用...
,您可以,例如:
my.wrapper2 <- function(dev, name, ...) {
dotargs <- list(...)
writeLines("my.wrapper2, called with the following extra arguments:")
print(dotargs)
## do nothing now...
}
给出了:
> my.wrapper2(pdf, "foo.pdf", height = 10, width = 5, pointsize = 8,
+ version = "1.3")
my.wrapper2, called with the following extra arguments:
$height
[1] 10
$width
[1] 5
$pointsize
[1] 8
$version
[1] "1.3"
那么你可以以编程方式提取你想要的参数以及你想要的东西。
我刚刚想到的其他可能有用的东西是你可以使用c
将额外的组件连接到列表上:
> c(filename = "name", list(height = 500, width = 500))
$filename
[1] "name"
$height
[1] 500
$width
[1] 500
因此,如果您真的想将do.call
应用于一组参数,那么
my.wrapper3 <- function(dev, name, ...) {
dotargs <- list(...)
## concatenate with name
callArgs <- c(filename = name, dotargs)
## use do.call
do.call(dev, args = callArgs)
}
但使用上面的my.wrapper
可以更轻松地实现这一目标。
答案 1 :(得分:1)
dev <- "png"
filename <- "foo.png"
width <- 480
height <- 480
opts <- c(width=width, height=height)
my.wrapper <- function(dev,name,opts) {
name <- list(filename=name)
do.call(dev, c(name, opts))
}
my.wrapper(dev, filename, opts)
请注意,仅当opts
是命名向量时才会起作用,因为do.call
需要带有命名条目的列表。
我认为你必须添加额外步骤的原因是c()
根据其参数的类型做不同的事情 - 如果你想要一个列表,它的一个参数必须是一个列表,否则它会对其所有参数进行必要的类型转换,以便它可以创建一个向量。