我经常遇到一些使自己陷入while循环的问题,但是却变得丑陋,我在这里问是否有一个优雅的解决方案,或者所有可能的解决方案都是丑陋的。有吗?
这是一个简化的示例:假设我们正在尝试查找函数f <- function(x){x^2}
的最小值以及找到该函数的位置。假设我们选择通过进行初步猜测x
并评估f(x)
来找到最小值。然后我们评估f(x-0.1)
和f(x+0.1)
。如果这些值之一都小于f(x)
,则我们的新猜测是argmin。我们重复直到这种移位不再减小值为止。
我想出的最好的解决方案是在循环外运行算法的第一次迭代的一部分。但这需要我从循环中复制代码,即用!!!!!!!
括起来的代码部分。
# function to minimize
f <- function(x){x^2}
# initial guess
x.current <- 1
f.current <- f(x.current)
# !!!!!!!!!!!!
# part of first iteration
x.guess <- c(x.current - 0.1, x.current + 0.1)
f.guess <- sapply(x.guess, f)
best.ind <- which.min(f.guess)
x.new <- x.guess[best.ind]
f.new <- f.guess[best.ind]
# !!!!!!!!!!!!
# part of first iteration and later iterations
while (f.new < f.current){
x.current <- x.new
f.current <- f.new
x.guess <- c(x.current - 0.1, x.current + 0.1)
f.guess <- sapply(x.guess, f)
best.ind <- which.min(f.guess)
x.new <- x.guess[best.ind]
f.new <- f.guess[best.ind]
}
print("best guess = ")
print(x.current)
是否有“更精细”的方法?
答案 0 :(得分:1)
dww指出了几种选择。第三个是初始化在循环的第一次迭代中以及在循环的测试条件中适当引用的变量的变量:
# function to minimize
f <- function(x){x^2}
# initialize values
x.new <- 1
f.new <- f(x.new)
f.current <- f.new + 0.1 # just to fulfill test condition
# part of first iteration and later iterations
while (f.new < f.current){
x.current <- x.new
f.current <- f.new
x.guess <- c(x.current - 0.1, x.current + 0.1)
f.guess <- sapply(x.guess, f)
best.ind <- which.min(f.guess)
x.new <- x.guess[best.ind]
f.new <- f.guess[best.ind]
}
print("best guess = ")
print(x.current)
答案 1 :(得分:1)
有多种方法可以处理这种情况。是“丑陋”还是“漂亮”是一个问题,因此与StackOverflow无关。尽管如此,我们可以对一些不同的选项进行一些概括:
一个普遍的经验法则是应该避免重复代码段。每当您在程序中的不同位置看到一系列重复的行时,就应该强烈考虑将这些行放入其自己的函数中并重复调用此函数。
通过使代码更简洁,并要求维护人员仅通读并理解该部分,有助于提高整体代码的可读性。
也许更重要的是,它还有助于代码的可维护性,因为对该代码段的任何更改都将自动传播到整个程序中。必须不得不寻找并更改重复代码段的每个实例,这不仅在编辑代码时令人沮丧,而且还是一个容易出错的过程。
这是您可以在此处应用此原理的一种方法,使用另一种技巧将函数调用放在循环条件表达式内,因此我们只需要在这里调用一次(尽管代码 inside 不能保证执行while
循环,处于其条件的代码必须始终至少执行一次:
# initial guess
x <- 1
fx <- f(x)
find.new = function(x){
x.new <- c(x - 0.1, x + 0.1)
f.new <- sapply(x.new, f)
best.ind <- which.min(f.new)
x.new <- x.new[best.ind]
f.new <- f.new[best.ind]
return(list(x=x.new, fx=f.new))
}
while ((new <- find.new(x))$fx < fx){
x <- new$x
fx <- new$fx
}
如果(在这种情况下)循环内有一些代码,我们总是希望至少在onse上执行,那么请考虑使用重复循环而不是while。然后,我们可以测试退出条件以更新值或退出循环。如果原始代码中重复的代码段不需要在程序中的其他任何地方执行,则比将其包装在自己的函数中更简洁
repeat {
x.new <- c(x - 0.1, x + 0.1)
f.new <- sapply(x.new, f)
best.ind <- which.min(f.new)
x.new <- x.new[best.ind]
f.new <- f.new[best.ind]
if (f.new < fx) {
x <- x.new
fx <- f.new
} else {
break
}
}