假设我要运行一个循环,直到满足条件为止,此时将保存结果并退出循环:

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::keeppurrr::reduce的要求。

这样考虑:mapreduce等是抽象,对应于更通用的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/

10-15 13:58