Как увеличить скорость кода vba, используя структуры данных, а не циклы for-next или индексирование и сопоставление функций листа? - PullRequest
0 голосов
/ 18 января 2019

Я уже разрешил несколько других, используя Application.Index с Application.WorksheetFunction.Match и уменьшил время выполнения с 7-8 секунд до миллисекунд. Но я чувствую, что есть еще возможности для улучшения.

Должен ли я использовать массив с Index и Match?

Мне также сказали использовать Scripting.Dictionary, но я ищу человека, который сможет продемонстрировать, как сделать это правильно в этом сценарии. Потому что в моей голове я должен заполнить словарь циклом, прежде чем я смогу его использовать, поэтому не будет ли он похожим по скорости?

'Production Quantity for Dashboard
For i = 2 To Total_rows_Prod
    For j = 2 To Total_rows_Dash
        If ThisWorkbook.Worksheets("Prod. Qty.").Cells(i, 5) = ThisWorkbook.Worksheets("Dashboard").Cells(j, 1) Then
           ThisWorkbook.Worksheets("Dashboard").Cells(j, 4) = ThisWorkbook.Worksheets("Dashboard").Cells(j, 4) + ThisWorkbook.Worksheets("Prod. Qty.").Cells(i, 31) / ThisWorkbook.Worksheets("Prod. Qty.").Cells(i, 4)
        End If
    Next j
Next i

После выполнения некоторых узких мест использование вложенного цикла for-next, как известно, является чрезвычайно медленным и плохим занятием, как показано ниже (время выполнения кода показано в строке 10):

enter image description here

Однако при использовании Index и Match при использовании только петли 1 for-next, как показано в приведенном ниже коде:

'Production Quantity for Dashboard
For i = 2 To Total_rows_Prod
    m = Application.Match(ThisWorkbook.Worksheets("Prod. Qty.").Cells(i, 5), ThisWorkbook.Worksheets("Dashboard").Range("A:A"), 0)
    If Not IsError(m) Then
        ThisWorkbook.Worksheets("Dashboard").Cells(Application.WorksheetFunction.Match(ThisWorkbook.Worksheets("Prod. Qty.").Cells(i, 5), ThisWorkbook.Worksheets("Dashboard").Range("A:A"), 0), 4) = ThisWorkbook.Worksheets("Dashboard").Cells(Application.WorksheetFunction.Match(ThisWorkbook.Worksheets("Prod. Qty.").Cells(i, 5), ThisWorkbook.Worksheets("Dashboard").Range("A:A"), 0), 4) + ThisWorkbook.Worksheets("Prod. Qty.").Cells(i, 31) / ThisWorkbook.Worksheets("Prod. Qty.").Cells(i, 4)
    End If
Next i

Время выполнения будет незначительным, как показано ниже (все еще в строке 10):

enter image description here

В последний раз (по состоянию на 21.01.19) я смог запустить все с заменами Index и Match: 2 секунды:

enter image description here

На более медленном нетбуке с процессором Pentium Atom выполнение того же кода занимает 26 секунд (в 13 раз больше). Поэтому мне интересно, есть ли способ сбить эти 26 секунд.

Любые улучшения, которые позволили бы минимизировать время выполнения, были бы великолепны. Надеюсь, сделаем это максимально быстрым.

Обновление от 23.02.19 (пересмотр кода):

Dim rangeProdQtySum As Range, rangeProdQtyPass As Range
Set rangeProdQtySum = ThisWorkbook.Worksheets("Prod. Qty.").Range("AE1:AE" & Total_rows_Prod)
Set rangeProdQtyPass = ThisWorkbook.Worksheets("Prod. Qty.").Range("D1:D" & Total_rows_Prod)

ReDim arrProdQtySum(1 To Total_rows_Prod) As Variant
ReDim arrProdQtyPass(1 To Total_rows_Prod) As Variant

arrProdQtySum = rangeProdQtySum
arrProdQtyPass = rangeProdQtyPass

ReDim arrProdQtyDash(1 To Total_rows_Dash) As Variant

'Production Quantity for Dashboard
For i = 2 To Total_rows_Prod
    m = Application.Match(arrProdQtyJTJN(i, 1), Application.Index(Application.WorksheetFunction.Transpose(arrDashInfo), 0, 1), 0)
    If Not IsError(m) Then
        arrProdQtyDash(Application.Match(arrProdQtyJTJN(i, 1), Application.Index(Application.WorksheetFunction.Transpose(arrDashInfo), 0, 1), 0)) = arrProdQtyDash(Application.Match(arrProdQtyJTJN(i, 1), Application.Index(Application.WorksheetFunction.Transpose(arrDashInfo), 0, 1), 0)) + arrProdQtySum(i, 1) / arrProdQtyPass(i, 1)
    End If
Next i

arrProdQtyDash(1) = "Production Quantity"
ThisWorkbook.Worksheets("Dashboard").Range("D1:D" & Total_rows_Dash) = Application.WorksheetFunction.Transpose(arrProdQtyDash)

Для массивов, минимизирующих использование циклов for-next, используйте index и match с комбинациями для arrays и запоминание переменных (присвоение ссылок на переменную), таймер выглядит следующим образом:

2/23/19 attempt

Тот же набор кодов, который я пробовал на более медленном компьютере с атомом Pentium, занимает 10 секунд, чтобы выполнить тот же код, как показано ниже:

improvement

Это примерно в 2,6 раза быстрее, чем просто использование индексов и кодов совпадений. Мне интересно, есть ли какие-либо улучшения, которые можно предложить для фрагмента кода, отображаемого здесь, потому что это узкое место (для выполнения атома pentium требуется 5 секунд или около 50% времени обработки).

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