Цикл справки и переход

У меня есть 3 рабочих листа. Первые 2 я конвертирую в два массива (array1 и array2), а затем выполняю вычисления между ними, чтобы создать третий.

Макрос, который я создал, использует этот фрагмент кода ---

Z = 1

For x = 1 To UBound(array1, 1)
    For y = 1 To UBound(array2, 1)
        If array1(x, 4) = 0 Then
            GoTo Line1
        End If
        If array1(x, 1) = array2(y, 1) And array1(x, 2) = array2(y, 3)Then
            If array1(x, 4) > array2(y, 5) Then
                array3(z, 1) = array1(x, 3)
            ElseIf array1(x, 4) = array2(y, 5) Or array1(x, 4) < array2(y, 5) Then
                array3(z, 1) = array1(x, 3)
            End If
            z = z + 1
        End If
    Next y
Line1:
Next x

Он берет часть array1 и пропускает ее через array2 и создает результат в array3

В основном, когда array1(x, 4) = 0, мне нужно, чтобы перейти к следующему X. Я не могу понять, как это зациклить без GoTo Line1.

Если я сдвину его вниз, то он продолжит перебирать array2(y) вместо перехода к следующему X. Если я передвину его выше, то y сбрасывается, и он снова проходит через цикл For y.

Также используется GoTo Line X, плохая практика в VBA. Должен ли я всегда стараться избегать его использования. Я довольно новичок в этом.


person UserX    schedule 18.02.2018    source источник
comment
goto может быть полезным, но он также безумно мощный, поэтому лучше убедиться, что вы все понимаете, прежде чем просто вставлять его в код. но в вашем случае вам может понадобиться его использовать   -  person Doug Coats    schedule 19.02.2018
comment
Пожалуйста, сделайте правильный отступ в коде и удалите пустые строки. Goto вообще никогда не нужен (за исключением операторов On Error Goto ...). Избегайте этого в обычном коде.   -  person Tomalak    schedule 19.02.2018
comment
@Tomalak это необходимо для этого кода? Я не уверен в другом способе форматирования этого   -  person UserX    schedule 19.02.2018
comment
Проверьте обратное и удалите переход и поместите код в сторону if.   -  person Scott Craner    schedule 19.02.2018
comment
@UserX Как я уже сказал, GoTo никогда не требуется. Его использование увеличивает вероятность ошибок в вашем коде и общую вероятность головной боли.   -  person Tomalak    schedule 19.02.2018
comment
Верно... Я не могу найти способ сделать это без него. @ScottCraner Я думаю, вы имеете в виду переместить goto if перед строкой For y и изменить его на Not = на 0? Когда я это делаю, x продолжает проходить через цикл y и не достигает If array3(x, 4) = 0. Из-за этого я получаю кучу нулей в своем массиве, потому что он обрабатывает логику, но он возвращает 0, потому что это то, что осталось в массиве3 (x, 4)   -  person UserX    schedule 19.02.2018
comment
Почему бы вам просто не использовать код в этом ответе ?   -  person DisplayName    schedule 19.02.2018
comment
@DisplayName да, я пробовал. Я думаю, что я неправильно форматировал, потому что ответ был общей формой кода, а не конкретным, поскольку я задал вопрос в целом. Я мог заставить работать редим, но не разрывал петлю там, где мне это было нужно. Сочетание того и другого кажется лучшим решением   -  person UserX    schedule 19.02.2018


Ответы (1)


Написание кода, основанного на GoTo, считается плохим стилем.

VB(A) имеет несколько встроенных конструкций, которые используются для обработки ошибок, требующих GoTo. Это неизбежно. Всех остальных следует избегать.

В этом случае это довольно просто, вы можете разорвать цикл For с помощью Exit For:

Z = 1

For x = 1 To UBound(array1, 1)
    For y = 1 To UBound(array2, 1)
        If array1(x, 4) = 0 Then Exit For
        If And array1(x, 1) = array2(y, 1) And array1(x, 2) = array2(y, 3) Then
            If array1(x, 4) > array2(y, 5) Then
                array3(z, 1) = array1(x, 3)
            ElseIf array1(x, 4) = array2(y, 5) Or array1(x, 4) < array2(y, 5) Then
                array3(z, 1) = array1(x, 3)
            End If
            z = z + 1            
        End If
    Next y
Next x

Альтернатива (имеет на один уровень вложенности больше):

For x = 1 To UBound(array1, 1)
    If array1(x, 4) <> 0 Then
        For y = 1 To UBound(array2, 1)
            If And array1(x, 1) = array2(y, 1) And array1(x, 2) = array2(y, 3) Then
                If array1(x, 4) > array2(y, 5) Then
                    array3(z, 1) = array1(x, 3)
                ElseIf array1(x, 4) = array2(y, 5) Or array1(x, 4) < array2(y, 5) Then
                    array3(z, 1) = array1(x, 3)
                End If
                z = z + 1            
            End If
        End If
    Next y
Next x
person Tomalak    schedule 18.02.2018
comment
спасибо @tomalak. Я не знал о выходе для командования. Приведет ли это к строке сразу после Next Y? - person UserX; 19.02.2018
comment
@UserX, да, будет. Имейте в виду, что Exit For существует только один уровень цикла For. - person 41686d6564; 19.02.2018
comment
@tomalak, стоит отметить, что GoTo не ВСЕГДА плохо. Да, вероятно, это плохо в 99% случаев, но иногда это может быть полезно, если только используется для перехода вперед. Примером этого может быть разрыв вложенных циклов. И да, альтернативой было бы использование отдельной функции, но с несколькими локальными переменными, в итоге получился бы намного более сложный код, а использование GoTo в таком случае не причинило бы никакого вреда. - person 41686d6564; 19.02.2018
comment
Когда вы достаточно хороши, чтобы распознать 1% вариантов использования (на самом деле, вероятно, намного меньше), где GoTo может быть оправдано использование, тогда вам не нужно спрашивать об этом. Пока вы должны спрашивать, вы недостаточно хороши и никогда не должны использовать это, очень просто. Лично я еще не нашел ни одного действительного варианта использования, у которого не было бы лучшей альтернативы посредством рефакторинга. - person Tomalak; 19.02.2018