#excel #vba #loops #for-loop
#excel #vba #циклы #цикл for
Вопрос:
У меня есть вложенный цикл for, который повторяет годы рождения (с 1919 по 2001 год) для двух разных людей.
Цель состоит в том, чтобы найти каждую возрастную комбинацию (на основе дат рождения) для двух человек.
Проблема, с которой я сталкиваюсь, заключается в том, что возраст пользователя во вложенном цикле (цикл с переменной j), кажется, иногда повторяется случайным образом без шаблона.
Например, каждая комбинация, когда человеку N от 100 до 20 лет, работает нормально без повторного значения возраста для человека J. Затем внезапно, когда человеку N от 19 лет, человеку J возрастет от 100 до 50 лет, затем дважды будет 49 лет, а затем возрастет до 47.
Ниже приведен мой код:
Sub ChangeDOB()
Application.ScreenUpdating = False
Dim n As Long
Dim i As Long
Dim j As Long
i = 2
For n = 1919 To 2001
Sheets("Inputs").Range("E6").FormulaR1C1 = "1/15/" amp; n
'j = 1919
For j = 1919 To 2001
Sheets("FF Tool Rates").Range("B" amp; i).Value = Sheets("Inputs").Range("E7").Value
Sheets("Inputs").Range("E10").FormulaR1C1 = "1/15/" amp; j
Sheets("FF Tool Rates").Range("C" amp; i).Value = Sheets("Inputs").Range("E11").Value
Sheets("FF Tool Rates").Range("D" amp; i).Value = Sheets("Inputs").Range("S8").Value
i = i 1
Next j
Next n
Application.ScreenUpdating = True
End Sub
Формула во входных данных!E7 вычисляет возраст пользователя N. Формула во входных данных!E11 вычисляет возраст пользователя J. Формула во входных данных!S8 вычисляет значение, основанное на возрасте двух человек. Я надеюсь, что это добавляет ясности.
Ниже приведен пример ожидаемого результата:
Person N Age Person J Age
90 90
90 89
90 88
90 87
90 86
90 85
90 84
90 83
90 82
90 81
Ниже приведен пример результата ошибки (смотрите, как дважды отображается возраст 85):
Person N Age Person J Age
33 90
33 89
33 88
33 87
33 85 <-should've been 86
33 85
33 84
33 83
33 82
33 81
Изначально я думал, что это способ настройки Excel, который вычисляет возраст на основе дат рождения. Но если я вручную ввел год в ячейки, Excel выдает неповторяющиеся результаты. Таким образом, возраст 85 не отображается дважды при ручном вводе.
Похоже, что нет шаблона относительно того, когда появляется эта ошибка, и если я иногда повторно запускаю код, ошибки не будет, а иногда ошибка появляется где-то еще. Вот почему мне было сложно это отладить.
Любые предложения или рекомендации о том, где я мог что-то упустить или если я перепутал какую-либо логику в своем коде?
Заранее благодарю вас!
Комментарии:
1. a) Ваши конструкции даты в
"1/15/" amp; n
стиле должны бытьDateSerial(n, 1, 15)
иDateSerial(j, 1, 15)
в ячейках, отформатированных как даты. б) Кажется, у вас есть формулы на входных данных! E7, входные данные! E11 и входные данные! S8. Вы должны были включить их, поскольку ваши результаты зависят от них.2. (1/2) Привет! Спасибо за ваш комментарий и приношу извинения за то, что не перезвонил вам ранее по этому поводу. a.) Я обновил формулу, чтобы использовать функцию DateSerial. После применения этого изменения в выходных данных все еще остаются ошибки. б.) Часть электронной таблицы, в которой я использую VBA, является небольшой частью гораздо большего файла. Следовательно, формулы во входных данных!E7, 11 и S8 связывают другие части электронной таблицы, поэтому сами формулы бесполезны, если вы не просматриваете электронную таблицу в целом.
3. (2/2) Я вручную проверил ошибки, поиграв с вводом year, который выдает мне неправильную ошибку. Входные данные! E7, входные данные! E11 и входные данные! Все S8 выдали правильные результаты во время ручного тестирования, поэтому я не думаю, что формула в этих ячейках является причиной ошибки. Просто взглянув на логику кода, можете ли вы обнаружить какие-либо логические ошибки? Возможно ли, что VBA Excel запускается «слишком быстро», чтобы формулы могли обработать изменение, и это приводит к неправильному значению?
4. Для пояснения: формула во входных данных! E7 вычисляет возраст пользователя N. Формула во входных данных! E11 вычисляет возраст пользователя J. Формула во входных данных! S8 вычисляет значение, основанное на возрасте двух человек. Я надеюсь, что это добавляет ясности.
Ответ №1:
Я думаю, что у меня была точно такая же проблема, ваш вопрос был единственным, который я нашел, и казалось, что его ответ мог бы мне помочь. Жаль, что ответов не было.
В итоге я исправил это, так что, надеюсь, это поможет другим:
У меня есть рабочая книга, которая вычисляет цены на продукты на основе 4 переменных (которые сами по себе разделены между разными листами и другими книгами). Переменная a
имеет 25 возможностей, b
имеет 52, c
имеет 3 и d
имеет 6. Это дает мне 22 464 различных ценовых варианта. В моем коде есть 4 вложенных цикла для печати каждой возможности в другой строке, поэтому я могу импортировать выходные данные в другую систему.
Проблема, с которой я столкнулся, заключалась в том, что, помимо того, что запуск на высокопроизводительном компьютере занимал почти 30 минут, я случайным образом получал строки с неправильными данными.
Мой (неподтвержденный) диагноз заключался в том, что из-за того, что в For
циклах выполнялось много вычислений в других местах листа (фактически, в любом месте Excel), иногда VBA продолжал итерацию и заполнял следующую строку до того, как у источника была возможность обновить.
Вот почему при пошаговой отладке ошибка не отображалась, и почему она была прерывистой и казалась случайной даже при запуске кода в целом.
Я начал с использования, With
чтобы упростить свой код и избежать перебора VBA всего Workbooks
и Worksheets
массивов с каждой строкой кода. Я также создал Excel.Workbook
, Excel.Worksheet
и Excel.Range
переменные для каждой из моих многочисленных ссылок.
Что в конечном итоге, похоже, исправило это, хотя, добавлялось Application.Calculation = xlCalculationManual
к началу подраздела и Application.Calculate
к соответствующей точке во вложенных циклах. Я добавил проверку на Application.CalculationState
, а затем на DoEvents
, но я даже не уверен, как проверить, работает ли это.
Вот соответствующая часть кода:
Sub test()
'
' (Variable declarations suppressed)
'
Application.ScreenUpdating = False
'Set to manual
Application.Calculation = xlCalculationManual
For a = 0 To 22464
rngTabCusto.Value = wksCalculos.Cells(a / 936 23, 28).Value
For b = 0 To 918
rngFrete.Value = wksFrete.Cells(b / 18 4, 1).Value
For c = 0 To 12
rngTipoFat.Value = wksCalculos.Cells(c / 6 3, 3).Value
'
' Calculate sheets after changing variables
'
Application.Calculate
'
' Waits until calculations are done
'
If Not Application.CalculationState = xlDone Then
DoEvents
End If
'
' Prints calculation results
'
With wksDescontos
For d = 0 To 5
.Cells(a b c d 2, 1).Value = rngEstab.Value
.Cells(a b c d 2, 2).Value = wksOrcamento.Cells(2, d 2).Value
.Cells(a b c d 2, 3).Value = rngContrib.Value
.Cells(a b c d 2, 4).Value = wksRegiao.Cells(b / 18 2, 1).Value
.Cells(a b c d 2, 5).Value = wksRegiao.Cells(b / 18 2, 2).Value
.Cells(a b c d 2, 6).Value = wksOrcamento.Cells(4, d 2).Value
.Cells(a b c d 2, 7).Value = rngTabOrc.Value
.Cells(a b c d 2, 8).Value = data
.Cells(a b c d 2, 11).Value = rngFat.Value
Next d
End With
c = c 5
Next c
b = b 17
Next b
a = a 935
Next a
'Reset
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub