Выходные данные вложенного for-цикла Excel VBA реплицированы / неправильные результаты

#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