如何从一个函数返回多个值?
仍然试图进入R逻辑…什么是“最好”的方式来解压(在LHS上)返回多个值的函数的结果?
我显然不能这样做:
R> functionReturningTwoValues <- function() { return(c(1, 2)) } R> functionReturningTwoValues() [1] 1 2 R> a, b <- functionReturningTwoValues() Error: unexpected ',' in "a," R> c(a, b) <- functionReturningTwoValues() Error in c(a, b) <- functionReturningTwoValues() : object 'a' not found
我必须真的做到以下几点吗?
R> r <- functionReturningTwoValues() R> a <- r[1]; b <- r[2]
或者R程序员会写更类似这样的东西:
R> functionReturningTwoValues <- function() {return(list(first=1, second=2))} R> r <- functionReturningTwoValues() R> r$first [1] 1 R> r$second [1] 2
—编辑回答谢恩的问题—
我并不需要给结果值部分命名。 我将一个聚合函数应用到第一个组件,另一个应用到第二个组件( min
和max
,如果这两个组件是相同的函数,我不需要将它们分开)。
(1)列表[…] < –我十多年前发布了这个r-help 。 它不需要特殊的操作符,但是需要使用如下list[...]
来书写左侧:
# first run source command shown below or else install and load gsubfn dev pkg (see Note) list[a, b] <- functionReturningTwoValues()
注:最近的
list
已被添加到gsubfn软件包的开发版本中,可以通过以下方式获取:source("https://raw.githubusercontent.com/ggrothendieck/gsubfn/master/R/list.R")
或者安装并加载gsubfn github开发包(使用devtools包):
devtools::install_github("ggrothendieck/gsubfn") library(gsubfn)
如果你只需要第一个或第二个组件,这些都是工作的:
list[a] <- functionReturningTwoValues() list[a, ] <- functionReturningTwoValues() list[, b] <- functionReturningTwoValues()
(当然,如果你只需要一个值,那么functionReturningTwoValues()[[1]]
或者functionReturningTwoValues()[[2]]
就足够了。
有关更多示例,请参阅引用的r-help线程。
(2)如果意图仅仅是随后将多个值组合起来,并且返回值被命名,那么简单的替代scheme是使用:
myfun <- function() list(a = 1, b = 2) list[a, b] <- myfun() a + b # same with(myfun(), a + b)
(3)附加另一种替代方法是附加:
attach(myfun()) a + b
ADDED: attach
我不知何故,在互联网上这个聪明的黑客绊倒…我不知道是否讨厌或美丽,但它可以让你创build一个“神奇的”运算符,允许您将多个返回值解压缩到自己的variables。 这里定义了 :=
函数,后面包含了后代:
':=' <- function(lhs, rhs) { frame <- parent.frame() lhs <- as.list(substitute(lhs)) if (length(lhs) > 1) lhs <- lhs[-1] if (length(lhs) == 1) { do.call(`=`, list(lhs[[1]], rhs), envir=frame) return(invisible(NULL)) } if (is.function(rhs) || is(rhs, 'formula')) rhs <- list(rhs) if (length(lhs) > length(rhs)) rhs <- c(rhs, rep(list(NULL), length(lhs) - length(rhs))) for (i in 1:length(lhs)) do.call(`=`, list(lhs[[i]], rhs[[i]]), envir=frame) return(invisible(NULL)) }
有了这个,你可以做你以后的事情:
functionReturningTwoValues <- function() { return(list(1, matrix(0, 2, 2))) } c(a, b) := functionReturningTwoValues() a #[1] 1 b # [,1] [,2] # [1,] 0 0 # [2,] 0 0
我不知道我的感受如何。 也许你可能会发现它在你的交互式工作区中很有帮助。 使用它来构build(重新)可用的库(用于大众消费)可能不是最好的想法,但是我想这取决于你。
你知道他们对责任和权力所说的话
通常我把输出包装成一个非常灵活的列表(你可以有任意数字,string,向量,matrix,数组,列表,对象的输出)
如此:
func2<-function(input) { a<-input+1 b<-input+2 output<-list(a,b) return(output) } output<-func2(5) for (i in output) { print(i) } [1] 6 [1] 7
这个问题没有正确的答案。 我真的依赖于你在做什么数据。 在上面的简单例子中,我强烈build议:
- 保持尽可能简单的事情。
- 只要有可能,最好的做法是保持你的函数向量化。 这从长远来看提供了最大的灵活性和速度。
上面的值1和2是否有名字是重要的? 换句话说,为什么在这个例子中,1和2被称为a和b,而不仅仅是r [1]和r [2]? 在这种情况下要理解的一个重要的事情是,a和b 也是长度为1的vector。所以在做这个任务的过程中,并没有真正改变任何东西,除了有两个新的向量不需要下标被引用:
> r <- c(1,2) > a <- r[1] > b <- r[2] > class(r) [1] "numeric" > class(a) [1] "numeric" > a [1] 1 > a[1] [1] 1
如果您宁愿引用字母而不是索引,也可以将名称分配给原始向量:
> names(r) <- c("a","b") > names(r) [1] "a" "b" > r["a"] a 1
[编辑]考虑到你将分别应用最小和最大的每个向量,我会build议使用matrix(如果a和b将是相同的长度和相同的数据types)或数据框架(如果a和b将相同的长度,但可以是不同的数据types),或者像上一个例子那样使用一个列表(如果它们可以具有不同的长度和数据types)。
> r <- data.frame(a=1:4, b=5:8) > r ab 1 1 5 2 2 6 3 3 7 4 4 8 > min(r$a) [1] 1 > max(r$b) [1] 8
functionReturningTwoValues <- function() { results <- list() results$first <- 1 results$second <-2 return(results) } a <- functionReturningTwoValues()
我认为这是有效的。
列表似乎是完美的这个目的。 例如,在你将有的function
x = desired_return_value_1 # (vector, matrix, etc) y = desired_return_value_2 # (vector, matrix, etc) returnlist = list(x,y...) } # end of function
主程序
x = returnlist[[1]] y = returnlist[[2]]
是的,你的第二个和第三个问题 – 这是你需要做的,因为你不能在任务的左边有多个“左值”。
如何使用分配?
functionReturningTwoValues <- function(a, b) { assign(a, 1, pos=1) assign(b, 2, pos=1) }
您可以传递想要通过引用传递的variables的名称。
> functionReturningTwoValues('a', 'b') > a [1] 1 > b [1] 2
如果您需要访问现有的值,那么assign
的逆向就是get
。
[A]如果foo和bar都是单个数字,那么c(foo,bar)就没有错。 你也可以命名组件:c(Foo = foo,Bar = bar)。 所以你可以通过res [1],res [2];来访问结果'res'的组件。 或者在指定的情况下作为res [“Foo”],res [“BAR”]。
[B]如果foo和bar是相同types和长度的向量,那么返回cbind(foo,bar)或rbind(foo,bar)也没有错。 同样可以名字。 在'cbind'的情况下,你可以使用res [,1],res [,2]或res [,“Foo”],res [,“Bar”]来访问foo和bar。 你也可能更喜欢返回一个数据框而不是matrix:
data.frame(Foo=foo,Bar=bar)
并以res $ Foo,res $ Bar的forms访问它们。 如果foo和bar的长度相同但不是相同的types(例如,foo是一个数字的向量,而是一个string的向量),这也可以很好地工作。
[C]如果上面的foo和bar不够方便的组合,那么你肯定会返回一个列表。
例如,你的函数可能适合线性模型,也可以计算预测值,所以你可以有
LM<-lm(....) ; foo<-summary(LM); bar<-LM$fit
然后你将return list(Foo=foo,Bar=bar)
,然后访问摘要作为res $ Foo,预测值为res $ Bar
来源: http : //r.789695.n4.nabble.com/How-to-return-multiple-values-in-a-function-td858528.html
如果要将函数的输出返回到全局环境,则可以使用list2env
,如下例所示:
myfun <- function(x) { a <- 1:x b <- 5:x df <- data.frame(a=a, b=b) newList <- list("my_obj1" = a, "my_obj2" = b, "myDF"=df) list2env(newList ,.GlobalEnv) } myfun(3)
此function将在您的全球环境中创build三个对象:
> my_obj1 [1] 1 2 3 > my_obj2 [1] 5 4 3 > myDF ab 1 1 5 2 2 4 3 3 3
要从一个函数获得多个输出并将它们保持为所需的格式,可以将输出保存到硬盘上(在工作目录中),然后从函数外部加载它们:
myfun <- function(x) { df1 <- ... df2 <- ... save(df1, file = "myfile1") save(df2, file = "myfile2") } load("myfile1") load("myfile2")
我放了一个R包zeallot来解决这个问题。 zeallot包含一个多重赋值或解包赋值运算符, %<-%
。 运算符的LHS是任意数量的variables,用c()
调用构build。 运算符的RHS是一个vector,列表,数据框,date对象或任何具有实现的destructure
方法的自定义对象(请参阅?zeallot::destructure
)。
这里有一些基于原始post的例子,
library(zeallot) functionReturningTwoValues <- function() { return(c(1, 2)) } c(a, b) %<-% functionReturningTwoValues() a # 1 b # 2 functionReturningListOfValues <- function() { return(list(1, 2, 3)) } c(d, e, f) %<-% functionReturningListOfValues() d # 1 e # 2 f # 3 functionReturningNestedList <- function() { return(list(1, list(2, 3))) } c(f, c(g, h)) %<-% functionReturningNestedList() f # 1 g # 2 h # 3 functionReturningTooManyValues <- function() { return(as.list(1:20)) } c(i, j, ...rest) %<-% functionReturningTooManyValues() i # 1 j # 2 rest # list(3, 4, 5, ..)
查看封装小插曲以获取更多信息和示例。