Прекращение функции на основе применения на ранней стадии (похоже на прерывание?) - PullRequest
10 голосов
/ 07 февраля 2011

Я ищу способ прекратить применение функции на раннем этапе при некоторых условиях.Используя цикл for, что-то вроде:

FDP_HCFA = function(FaultMatrix, TestCosts, GenerateNeighbors, RandomSeed) {    
  set.seed(RandomSeed)

  ## number of tests, mind the summary column
  nT = ncol(FaultMatrix) - 1
  StartingSequence = sample(1:nT)
  BestAPFD = APFD_C(StartingSequence, FaultMatrix, TestCosts)
  BestPrioritization = StartingSequence
  MakingProgress = TRUE
  NumberOfIterations = 0
  while(MakingProgress) {
    BestPrioritizationBefore = BestPrioritization
    AllCurrentNeighbors = GenerateNeighbors(BestPrioritization)

    for(CurrentNeighbor in AllCurrentNeighbors) {
      CurrentAPFD = APFD_C(CurrentNeighbor, FaultMatrix, TestCosts)

      if(CurrentAPFD > BestAPFD) {
        BestAPFD = CurrentAPFD
        BestPrioritization = CurrentNeighbor            
        break
      }
    }

    if(length(union(list(BestPrioritizationBefore),
                    list(BestPrioritization))) == 1)
      MakingProgress = FALSE

    NumberOfIterations = NumberOfIterations + 1
  }
}

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

Ответы [ 3 ]

17 голосов
/ 07 февраля 2011

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

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

Чтобы понять разницу, не читайте apply(1:3,afunc) как for(i in 1:3) afunc(i), а как

afunc(1)
afunc(2)
afunc(3)

в одном (блочном) утверждении.Это лучше отражает то, что вы делаете.Эквивалент break в apply просто не имеет смысла, так как это скорее блок кода, чем цикл.

2 голосов
/ 28 февраля 2011

Я также искал способ вырваться рано из примените основанный цикл, и нашел этот поток.

Даже если некоторые люди утверждают, что заявление должно рассматриваться как «код блока», а не «цикл», я все еще думаю, что это будет полезно иметь возможность вырваться из него. Причина в что функции на основе применения, кажется, выполняются намного быстрее, что-то вроде в 10-100 раз быстрее, чем цикл for. Много раз Я запустил простые фрагменты для циклов, которые не делаются после более чем на несколько минут, в то время как заявка, кажется, получает то же самое работа сделана за считанные секунды.

2 голосов
/ 07 февраля 2011

Помимо того, что ваш пример кода заработал * Я думаю, что это очевидный случай, когда цикл является правильным выбором. Хотя R может применять функцию ко всему вектору переменных [РЕДАКТИРОВАТЬ: но вы должны решить, что они перед применением], в этом случае я бы использовал цикл while, чтобы избежать затрат на выполнение ненужных повторений. Предостережение: я знаю, что циклы for выгодно сравнивались с apply в тестах синхронизации, но я не видел аналогичного теста для while. Проверьте некоторые параметры на http://cran.r -project.org / doc / manual / R-lang.html # Control-структура .

while ( *statement1* ) *statement2*

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...