假设我要运行一个循环,直到满足条件为止,此时将保存结果并退出循环:
library(tidyverse)
for (i in 1:5) {
df <- iris %>% select(i) %>% head(2)
if (names(df) == "Petal.Width") {
out <- df
break
}
}
out
如何在不评估每个i的情况下使用
purr::map
重写此代码?进行以下操作即可得到所需的结果,但必须评估5次,而for循环仅进行3次:
fun <- function(x) {
df <- iris %>% select(x) %>% head(2)
if (names(df) == "Petal.Width") {
return(df)
}
}
map_df(1:5, fun)
最佳答案
没有对等的东西。实际上,使map
(及类似函数)在可读性方面优于常规循环的一件事是,它们具有绝对可预测的行为:它们将对每个元素仅执行一次函数,无异常(exception)(除非,如果有,一个异常(exception):您可以通过stop
提出条件以使执行短路,但这是极少建议的)。
相反,您的案例并不需要map
,而是需要遵循purrr::keep
或purrr::reduce
的要求。
这样考虑:map
,reduce
等是抽象,对应于更通用的for
循环的特定特殊情况。他们的目的是弄清正在处理哪种特殊情况。作为程序员,您的任务便是找到正确的抽象。
在您的特定情况下,我可能会使用dplyr完全重写该语句,因此很难提供“最佳” purrr解决方案:最佳解决方案是不使用purrr。也就是说,您可以按以下方式使用purrr::detect
:
names(iris) %>%
detect(`==`, 'Sepal.Width') %>%
`[`(iris, .) %>%
head(2)
或者
seq_along(iris) %>%
detect(~ names(iris[.x]) == 'Sepal.Width') %>%
`[`(iris, .) %>%
head(2)
…但实际上,这里是dplyr供比较:
iris %>%
select(Sepal.Width) %>%
head(2)
关于r - 在purrr::map中相当于 `break`,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54653415/