使用进度条包装到FOR循环 [英] Wrapper to FOR loops with progress bar

查看:161
本文介绍了使用进度条包装到FOR循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我喜欢在为循环运行缓慢的时使用进度条。这可以很容易地与几个帮手完成,但是我喜欢从 tcltk 包中的 tkProgressBar

一个小例子:

pb <- tkProgressBar(title = "Working hard:", min = 0, max = length(urls), width = 300)
for (i in 1:300) {
    # DO SOMETHING
    Sys.sleep(0.5)
    setTkProgressBar(pb, i, label=paste( round(i/length(urls)*100, 0), "% ready!"))
}
close(pb)

我想设置一个小功能来存储在我的 .Rprofile 中,命名为 forp (as:for循环带进度条),调用就像 for ,但使用自动添加的进度条 - 但不幸的是不知道如何实现和抓住循环函数的 expr 部分。我有一些实验与 do.call 但没有成功:(

And I would like to set up a small function to store in my .Rprofile named to forp (as: for loop with progressbar), to call just like for but with auto added progress bar - but unfortunately have no idea how to implement and grab the expr part of the loop function. I had some experiments with do.call but without success :(

虚构的工作示例(其行为像一个 for 循环,但创建一个 TkProgressBar ,并在每次迭代中自动更新它):

Imaginary working example (which acts like a for loop but creates a TkProgressBar and auto updates it in each iteration):

forp (i in 1:10) {
    #do something
}

更新:我认为问题的核心是如何编写一个函数,不仅在函数后面的括号中有参数(如: foo(bar)),还可以处理在括号后指定的 expr ,如: foo(bar)expr

UPDATE: I think the core of the question is how to write a function which no only have parameters in the parentheses after the function (like: foo(bar)), but also can handle expr specified after the closing parentheses, like: foo(bar) expr.

BOUNTY OFFER 会去任何可以修改我建议的功能像的语法一样工作,例如

BOUNTY OFFER: would go to any answer that could modify my suggested function to work like the syntax of basic for loops. E.g. instead of

> forp(1:1000, {
+   a<-i
+ })
> a
[1] 1000

它可以像:

> forp(1:1000) {
+   a<-i
+ }
> a
[1] 1000

只是为了澄清任务再次:我们如何抓住一个函数调用的 {expression} ?我恐怕这是不可能的,但是会为了这个利益而离开赏金几天:)

Just to clarify the task again: how could we grab the { expression } part of a function call? I am afraid of that this is not possible, but will leave on the bounty for a few days for the pros :)

推荐答案

我的解决方案非常类似于Andrie的,除了它使用base R,我再次提出他的意见,需要在函数中包装你想要做的,随后需要使用< < - code>在更高的环境中修改东西。

My solution is very similar to Andrie's except it uses base R, and I second his comments on the need to wrap what you want to do in a function and the subsequent need to use <<- to modify stuff in a higher environment.

这是一个不起作用的功能,并且缓慢执行:

Here's a function that does nothing, and does it slowly:

myfun <- function(x, text) {
  Sys.sleep(0.2)
  cat("running ",x, " with text of '", text, "'\n", sep="")
  x
}

这是我的 forp 函数。请注意,无论我们实际上是循环,而是循环遍历序列 1:n ,并在循环中获得正确的条件。

Here's my forp function. Note that regardless of what we're actually looping over, it instead loops over the sequence 1:n instead and get the right term of what we actually want within the loop. plyr does this automatically.

library(tcltk)
forp <- function(x, FUN, ...) {
  n <- length(x)
  pb <- tkProgressBar(title = "Working hard:", min = 0, max = n, width = 300)
  out <- vector("list", n)
  for (i in seq_len(n)) {
    out[[i]] <- FUN(x[i], ...)
    setTkProgressBar(pb, i, label=paste( round(i/n*100, 0), "% ready!"))
  }
  close(pb)
  invisible(out)
}

可以使用 forp ,如果我们要做的只是调用 myfun

x <- LETTERS[1:5]
for(xi in x) myfun(xi, "hi")
forp(x, myfun, text="hi")

如果我们想要修改某些东西,可以使用它们。

And here's how they might be used if we want to modify something along the way.

out <- "result:"
for(xi in x) {
  out <- paste(out, myfun(xi, "hi"))
}

out <- "result:"
forp(x, function(xi) {
    out <<- paste(out, myfun(xi, "hi"))
})

对于这两个版本,结果是

For both versions the result is

> out
[1] "result: A B C D E"

编辑:看到你的(daroczig)解决方案,我有另一个想法可能不是那么笨重,这是评估父框架中的表达式。这使得更容易允许除 i 之外的值(现在使用索引参数指定),尽管如此现在我不认为它处理一个函数作为表达式,虽然只是放在而不是一个for循环,不要紧。

After seeing your (daroczig's) solution, I have another idea that might not be quite so unwieldy, which is to evaluate the expression in the parent frame. This makes it easier to allow for values other than i (now specified with the index argument), though as of right now I don't think it handles a function as the expression, though just to drop in instead a for loop that shouldn't matter.

forp2 <- function(index, x, expr) {
  expr <- substitute(expr)
  n <- length(x)
  pb <- tkProgressBar(title = "Working hard:", min = 0, max = n, width = 300)
  for (i in seq_len(n)) {
    assign(index, x[i], envir=parent.frame())
    eval(expr, envir=parent.frame())
    setTkProgressBar(pb, i, label=paste( round(i/n*100, 0), "% ready!"))
  }
  close(pb)
}

从上面运行我的例子的代码将是

The code to run my example from above would be

out <- "result:"
forp2("xi", LETTERS[1:5], {
    out <- paste(out, myfun(xi, "hi"))
})

,结果是一样的。

其他编辑,根据您的赏金报价中的其他信息:

ANOTHER EDIT, based on the additional information in your bounty offer:

语法 forX(1:1000) %doX $ {expression} 是可能的;这就是 foreach 软件包。我现在太懒了,把它从你的解决方案中建造出来,但是建立我的,可能看起来像这样:

The syntax forX(1:1000) %doX$ { expression } is possible; that's what the foreach package does. I'm too lazy right now to build it off of your solution, but building off mine, it could look like this:

`%doX%` <- function(index, expr) {
  x <- index[[1]]
  index <- names(index)
  expr <- substitute(expr)
  n <- length(x)
  pb <- tkProgressBar(title = "Working hard:", min = 0, max = n, width = 300)
  for (i in seq_len(n)) {
    assign(index, x[i], envir=parent.frame())
    eval(expr, envir=parent.frame())
    setTkProgressBar(pb, i, label=paste( round(i/n*100, 0), "% ready!"))
  }
  close(pb)
  invisible(out)
}

forX <- function(...) {
  a <- list(...)
  if(length(a)!=1) {
    stop("index must have only one element")
  }
  a
}

然后使用语法是这样,结果与上述相同。

Then the use syntax is this, and the result is the same as above.

out <- "result:"
forX(xi=LETTERS[1:5]) %doX% {
  out <- paste(out, myfun(xi, "hi"))
}
out

这篇关于使用进度条包装到FOR循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆