如何从一个函数返回多个值?

仍然试图进入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 

—编辑回答谢恩的问题—

我并不需要给结果值部分命名。 我将一个聚合函数应用到第一个组件,另一个应用到第二个组件( minmax ,如果这两个组件是相同的函数,我不需要将它们分开)。

(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是否有名字是重要的? 换句话说,为什么在这个例子中,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, ..) 

查看封装小插曲以获取更多信息和示例。