如何从返回多个值的函数中分配?

mar*_*omo 208 r return-value variable-assignment multiple-results assign

仍然试图进入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
Run Code Online (Sandbox Code Playgroud)

我真的必须做以下事吗?

R> r <- functionReturningTwoValues()
R> a <- r[1]; b <- r[2]
Run Code Online (Sandbox Code Playgroud)

或者R程序员会写更像这样的东西:

R> functionReturningTwoValues <- function() {return(list(first=1, second=2))}
R> r <- functionReturningTwoValues()
R> r$first
[1] 1
R> r$second
[1] 2
Run Code Online (Sandbox Code Playgroud)

---编辑回答谢恩的问题---

我真的不需要给结果值部分命名.我申请一个聚合函数的第一个组件和其他到第二组件(minmax,如果它是我不需要分裂他们两个组件功能相同).

G. *_*eck 175

(1)列表[...] < -我十多年前在r-help上发布了这个.从那以后它被添加到gsubfn包中.它不需要特殊的操作符,但需要使用list[...]如下方式编写左侧:

library(gsubfn)  # need 0.7-0 or later
list[a, b] <- functionReturningTwoValues()
Run Code Online (Sandbox Code Playgroud)

如果您只需要第一个或第二个组件,这些组件也都可以使用:

list[a] <- functionReturningTwoValues()
list[a, ] <- functionReturningTwoValues()
list[, b] <- functionReturningTwoValues()
Run Code Online (Sandbox Code Playgroud)

(当然,如果你只需要一个值,那么functionReturningTwoValues()[[1]]或者functionReturningTwoValues()[[2]]就足够了.)

有关更多示例,请参阅引用的r-help线程.

(2)with 如果意图仅仅是随后组合多个值并且返回值被命名,那么一个简单的替代方法是使用with:

myfun <- function() list(a = 1, b = 2)

list[a, b] <- myfun()
a + b

# same
with(myfun(), a + b)
Run Code Online (Sandbox Code Playgroud)

(3)附加另一种选择是附:

attach(myfun())
a + b
Run Code Online (Sandbox Code Playgroud)

增加:withattach

  • 我接受了你的答案,因为"with",但是我无法重现你所描述的左侧使用"list"的内容,我得到的只是"object'a'not found" (24认同)
  • @ G.Grothendieck,你介意我把链接的内容放到你的答案中吗?我认为它会让人们更容易使用它. (11认同)
  • 我同意@ merlin2011; 如图所示,似乎这种语法嵌入到R base中. (11认同)
  • @ G.Grothendieck我同意merlin2011和knowah - 如果这里重要的实际代码(链接中引用的代码)在答案中,那将是最好的.提到结果对象不需要命名列表可能不是一个坏主意.在阅读您的实际代码之前,这让我困惑了一会儿.如上所述,答案说您需要在链接中运行代码,但大多数人不会立即阅读该代码,除非它直接在答案中 - 这给人的印象是这种语法在基础R中. (5认同)
  • 这个对我有用.你尝试了什么?您是否阅读了链接的帖子并关注它?你在那里定义了`list`和`[< - .result`吗? (4认同)
  • @newbie,在源端附近的`substitute`中替换< - with << - . (4认同)
  • 第一个是辉煌的.这应该嵌入到R base中 (2认同)
  • 真的不错,谢谢分享。遗憾的是它没有嵌入到R base 中。 (2认同)
  • 我强烈建议不要使用`attach()`。我遇到了多个问题(不是错误,只是非常不祥的警告!)。请参阅不建议使用“ attach()”的[讨论](http://www.r-bloggers.com/to-attach-or-not-attach-that-is-the-question/)。具体来说,Google R Style手册针对“ attach()”提供了以下建议:“使用attach时可能会产生很多错误。请避免。” (2认同)
  • 有没有计划将其推向CRAN版本? (2认同)

Ste*_*lou 68

我在某种程度上偶然发现了互联网上这个聪明的黑客...我不确定它是否令人讨厌或漂亮,但它可以让你创建一个"神奇"的运算符,它允许你将多个返回值解包到它们自己的变量中.该:=功能在此处定义,并包含在下面用于后代:

':=' <- 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)) 
}
Run Code Online (Sandbox Code Playgroud)

有了这些,你可以做你想做的事情:

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
Run Code Online (Sandbox Code Playgroud)

我不知道我对此感觉如何.也许您可能会发现它在交互式工作区中很有用.使用它来构建(重新)可用库(用于大众消费)可能不是最好的主意,但我想这取决于你.

......你知道他们对责任和权力的看法......

  • 此外,由于[data.table](http://cran.r-project.org/web/packages/data.table/index.html)包,我最近发布这个答案的时候,我不鼓励它以更加方便的方式使用`:=`运算符mucho :-) (9认同)

Fed*_*rgi 44

通常我将输出包装成一个列表,这是非常灵活的(你可以输出数字,字符串,向量,矩阵,数组,列表,对象的任意组合)

所以喜欢:

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
Run Code Online (Sandbox Code Playgroud)

  • 如果不是 output&lt;-func2(5) 我想在两个对象中得到结果怎么办?我试过 list("a","b") &lt;-func2(5) 但它不起作用。 (2认同)

小智 13

functionReturningTwoValues <- function() { 
  results <- list()
  results$first <- 1
  results$second <-2
  return(results) 
}
a <- functionReturningTwoValues()
Run Code Online (Sandbox Code Playgroud)

我觉得这很有效.


nte*_*tor 11

我整理了一个R包zeallot来解决这个问题.zeallot包括多个赋值或解包赋值运算符,%<-%.运算符的LHS是要分配的任意数量的变量,使用调用来构建c().运算符的RHS是向量,列表,数据框,日期对象或具有已实现destructure方法的任何自定义对象(请参阅参考资料?zeallot::destructure).

以下是基于原帖的一些示例,

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, ..)
Run Code Online (Sandbox Code Playgroud)

查看包装插图以获取更多信息和示例.

  • 不需要特殊语法,您可以像分配数字列表一样分配绘图对象列表。 (2认同)

Sha*_*ane 10

这个问题没有正确的答案.我真的取决于你在做什么数据.在上面的简单示例中,我强烈建议:

  1. 让事情尽可能简单.
  2. 只要有可能,最好的做法是保持函数的矢量化.从长远来看,这提供了最大的灵活性和速度.

上面的值1和2是否具有名称是否重要?换句话说,为什么在这个例子中重要的是1和2被命名为a和b,而不仅仅是r [1]和r [2]?在这种情况下要理解的一件重要事情是a和b 都是长度为1的向量.所以除了有2个不需要下标的新向量之外,你在制作这个赋值的过程中并没有真正改变任何东西.被引用:

> 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
Run Code Online (Sandbox Code Playgroud)

如果您希望引用字母而不是索引,也可以将名称分配给原始矢量:

> names(r) <- c("a","b")
> names(r)
[1] "a" "b"
> r["a"]
a 
1 
Run Code Online (Sandbox Code Playgroud)

[编辑]鉴于你将分别对每个向量应用min和max,我建议使用矩阵(如果a和b将是相同的长度和相同的数据类型)或数据帧(如果a和b将是相同的长度,但可以是不同的数据类型)或者使用像上一个例子中的列表(如果它们可以是不同的长度和数据类型).

> r <- data.frame(a=1:4, b=5:8)
> r
  a b
1 1 5
2 2 6
3 3 7
4 4 8
> min(r$a)
[1] 1
> max(r$b)
[1] 8
Run Code Online (Sandbox Code Playgroud)


raf*_*ira 7

如果要将函数的输出返回到全局环境,可以使用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)
Run Code Online (Sandbox Code Playgroud)

此函数将在您的全局环境中创建三个对象:

> my_obj1
  [1] 1 2 3

> my_obj2
  [1] 5 4 3

> myDF
    a b
  1 1 5
  2 2 4
  3 3 3
Run Code Online (Sandbox Code Playgroud)


Arn*_*old 5

列表看起来很完美.例如,你将拥有的功能

x = desired_return_value_1 # (vector, matrix, etc)

y = desired_return_value_2 # (vector, matrix, etc)

returnlist = list(x,y...)

}  # end of function
Run Code Online (Sandbox Code Playgroud)

主程序

x = returnlist[[1]]

y = returnlist[[2]]
Run Code Online (Sandbox Code Playgroud)

  • 如何在单个命令中分配两个变量,例如list(“ x”,“ y”)&lt;-returnlist()?我说这是因为,如果列表中有许多元素,那么您将需要多次运行整个函数,这会花费一些时间。 (3认同)