相当于purrr :: map中的`break`

Shi*_*obe 9 r dplyr purrr

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

library(tidyverse)

for (i in 1:5) {

  df <- iris %>% select(i) %>% head(2)

  if (names(df) == "Petal.Width") {
    out <- df
    break 

  }
}

out
Run Code Online (Sandbox Code Playgroud)

如何在purr::map不评估每个i的情况下重写它?

执行以下操作会得到我需要的结果,但必须评估5次,而for循环只需3次:

fun <- function(x) {

  df <- iris %>% select(x) %>% head(2)

  if (names(df) == "Petal.Width") {
  return(df)
  }
}

map_df(1:5, fun)
Run Code Online (Sandbox Code Playgroud)

Kon*_*lph 9

没有等价物.实际上,使map(和类似函数)在可读性方面优于一般循环的一件事是它们具有绝对可预测的行为:它们将为每个元素执行一次正确的函数,没有异常(除非,呃,如果有的话)例外:您可以通过stop短路执行来提高条件,但这很少是可取的).

相反,你的情况并没有要求map,它要求的东西沿着purrr::keeppurrr::reduce.

想想这样说:map,reduce,等都是对应于更一般的具体特例抽象for循环.他们的目的是弄清楚正在处理哪种特殊情况.作为程序员,您的任务就是找到正确的抽象.

在您的特定情况下,我可能会使用dplyr完全重写语句,因此给出"最佳"的purrr解决方案很难:最好的解决方案是不使用purrr.也就是说,您可以使用purrr::detect如下:

names(iris) %>%
    detect(`==`, 'Sepal.Width') %>%
    `[`(iris, .) %>%
    head(2)
Run Code Online (Sandbox Code Playgroud)

要么

seq_along(iris) %>%
    detect(~ names(iris[.x]) == 'Sepal.Width') %>%
    `[`(iris, .) %>%
    head(2)
Run Code Online (Sandbox Code Playgroud)

......但是真的,这里是比较的dplyr:

iris %>%
    select(Sepal.Width) %>%
    head(2)
Run Code Online (Sandbox Code Playgroud)