Как избежать кодирования первой итерации вне цикла while - PullRequest
0 голосов
/ 27 июня 2018

У меня часто бывают проблемы, которые поддаются циклам 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)

Есть ли "более хороший" способ сделать это?

Ответы [ 2 ]

0 голосов
/ 28 июня 2018

Существует множество способов справиться с этой ситуацией. Является ли кто-то «некрасивым» или «симпатичным» - это вопрос мнения, и поэтому не по теме для StackOverflow. Тем не менее, мы можем сделать некоторые обобщения о некоторых различных вариантах:

Вариант 1: переносить повторяющиеся строки в свои функции

Общее правило заключается в том, что следует избегать повторения сегментов кода. Всякий раз, когда вы видите последовательность строк, повторяющихся в разных местах вашей программы, следует строго рассмотреть возможность помещения этих строк в их собственную функцию и повторного вызова этой функции.

Это способствует удобочитаемости всего кода, делая его более лаконичным и требуя от сопровождающего только прочитать и понять этот раздел только один раз.

Возможно, что еще более важно, это также помогает в поддержке кода, потому что любые изменения в этом фрагменте будут автоматически распространяться по всей программе. Необходимость выслеживать и изменять каждый экземпляр повторяющегося фрагмента кода не только разочаровывает, когда дело доходит до редактирования кода, но и является потенциально подверженной ошибкам процедурой.

Вот один из способов, которым вы могли бы применить этот принцип здесь, используя дополнительный прием размещения функции внутри выражения условия цикла, так что нам нужно вызывать его только один раз здесь (хотя код внутри a Цикл 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
}

2 используйте вместо этого цикл повторения

Если, как и в этом случае, внутри цикла есть какой-то код, который мы всегда хотели бы выполнить хотя бы один раз, тогда рассмотрите возможность использования цикла повтора вместо 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
  }
}
0 голосов
/ 28 июня 2018

Как указано 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...