在下面显示的函数中,没有return
。但是,执行后,我可以确认正常输入d
的值。
没有return
。任何有关这方面的建议都将受到赞赏。
代码
#installed plotly, dplyr
accumulate_by <- function(dat, var) {
var <- lazyeval::f_eval(var, dat)
lvls <- plotly:::getLevels(var)
dats <- lapply(seq_along(lvls), function(x) {
cbind(dat[var %in% lvls[seq(1, x)], ], frame = lvls[[x]])
})
dplyr::bind_rows(dats)
}
d <- txhousing %>%
filter(year > 2005, city %in% c("Abilene", "Bay Area")) %>%
accumulate_by(~date)
答案 0 :(得分:3)
在该功能中,最后一项任务是创建&#39; dats&#39;与bind_rows(dats)
一起返回的内容我们不需要明确的return
语句。假设,如果要返回两个对象,我们可以将其放在list
在python
等某些语言中,为了提高内存效率,generators
使用yield
而不是在内存中创建整个输出,即考虑python
<中的两个函数/ p>
def get_square(n):
result = []
for x in range(n):
result.append(x**2)
return result
当我们运行它时
get_square(4)
#[0, 1, 4, 9]
同一个函数可以写成generator
。 <而不是return
任何东西,
def get_square(n):
for x in range(n):
yield(x**2)
运行功能
get_square(4)
#<generator object get_square at 0x0000015240C2F9E8>
通过使用list
进行投射,我们得到相同的输出
list(get_square(4))
#[0, 1, 4, 9]
答案 1 :(得分:3)
总有一个回归:)你不必明白它。
所有 R表达式都返回一些东西。包括控制结构和用户定义的函数。 (顺便说一句,控制结构只是函数,所以你可以记住所有东西都是值或函数调用,并且所有东西都计算为值)。
对于函数,返回值是在函数执行中计算的最后一个表达式。所以,对于
f <- function(x) 2 + x
当您致电f(3)
时,您将使用两个参数+
和2
调用函数x
。它们分别评估为2
和3
,因此`+`(2, 3)
评估为5
,这是f(3)
的结果。
当您调用return
函数时 - 请记住,这是一个函数 - 您只需提前保留函数的控制流。所以,
f <- function(x) {
if (x < 0) return(0)
x + 2
}
的工作方式如下:当您调用f
时,它将调用if
函数来确定在第一个语句中要执行的操作。 if
函数将评估x < 0
(这意味着使用参数<
和x
调用函数0
)。如果x < 0
为真,if
将评估return(0)
。如果为false,则会评估其else
部分(因为if
在函数方面具有特殊语法,因此未显示,但是NULL
)。如果x < 0
不成立,f
将评估x + 2
并返回该值。但是,如果x < 0
为真,if
函数将评估return(0)
。这是对函数return
的调用,参数为0
,该调用将终止f
的执行并生成结果0
。
小心return
。这是一个功能
f <- function(x) {
if (x < 0) return;
x + 2
}
是完全有效的R代码,但在x < 0
时不会返回。 if
调用只评估函数return
,但不会调用它。
return
函数也有一点特别之处在于它可以从控制结构的父调用返回。严格地说,return
并未在上面示例中f
的框架中进行评估,而是在if
次调用内部进行评估。它只是处理这个特殊所以它可以从f
返回。
对于非标准评估,这并不总是案例。
使用此功能
f <- function(df) {
with(df, if (any(x < 0)) return("foo") else return("bar"))
"baz"
}
你可能会认为
f(data.frame(x = rnorm(10)))
应返回"foo"
或"bar"
。毕竟,我们在if
语句中返回。但是,if
语句在with
内进行评估,并且不会以这种方式工作。该函数将返回baz
。
对于非本地回报,您需要使用callCC
,然后它会变得更具技术性(就好像这还不够技术)。
如果可以的话,尽量避免使用return
并依赖函数返回他们评估的最后一个表达式。
只是跟进下面关于循环的评论。当您调用循环时,您很可能会调用其中一个内置的基本函数。而且,是的,他们返回NULL
。但是你可以编写自己的,他们将遵循他们返回他们评估的最后一个表达式的规则。例如,您可以按照for
这样的方式实施while
:
`for` <- function(itr_var, seq, body) {
itr_var <- as.character(substitute(itr_var))
body <- substitute(body)
e <- parent.frame()
j <- 1
while (j < length(seq)) {
assign(x = itr_var, value = seq[[j]], envir = e)
eval(body, envir = e)
j <- j + 1
}
"foo"
}
这个函数肯定会返回"foo"
,所以这个
for(i in 1:5) { print(i) }
评估"foo"
。如果你想要它返回NULL
,你必须明确它(或者只是让返回值是while
循环的结果 - 如果它是原始的while
它返回NULL
)。
我想说的是,函数返回它们评估的最后一个表达式与函数定义的方式有关,而不是你如何调用它们。循环使用非标准求值,因此您为它们提供的循环体中的最后一个表达式可能是它们评估的最后一个值,也可能不是。对于原始循环,它不是。
除了他们特殊的语法之外,没有什么神奇的循环。他们遵循所有功能遵循的规则。使用非标准的评估,从函数调用中得出它们将要评估的最后一个表达式可能会有点棘手,因为函数体看起来就像函数评估的那样。在某种程度上,如果函数是合理的,但循环体不函数体。这是一个参数。如果它不是特殊语法,并且你必须提供循环体作为正常参数,那么可能会有更少的混淆。