Оптимизировать двойной l oop Excel VBA - PullRequest
0 голосов
/ 25 февраля 2020

Я хотел бы оптимизировать множество циклов, которые сравнивают 2 таблицы в моем коде.

Действительно, время выполнения очень велико, потому что в 2 таблицах есть около 1500 строк для сравнения. Итак, двойной l oop в конце кода просто выполняет 1500 * 1500 действий. Таким образом, 2 250 000 действий - это действительно слишком много.

Надеюсь, вы сможете мне помочь, я не нашел способа сделать что-то еще ...

Вот код:

'********************This code compare if some values are in the first table and not in the second one and then in the second one and not in the first one with 2 loops********************


x = DL_COMPARATIF + 4

For t = 2 To DL_COMPARATIF

If Application.WorksheetFunction.CountIf(Sheets("AFFRETEMENTS EN COURS").Range("T:T"), Sheets("COMPARATIF").Range("C" & t)) = 0 Then

        x = x + 1

        For k = 1 To 17

            Sheets("COMPARATIF").Cells(x, k) = Sheets("COMPARATIF").Cells(t, k)

        Next k

        Sheets("COMPARATIF").Range("R" & x) = "L'OT ne figure pas dans Excel."

        Sheets("COMPARATIF").Range("A" & x & ":S" & x).Interior.Color = RGB(221, 235, 247)

        Erreur_mois = True

End If

Next t

For t = 3 To DL_AFFRETEMENT

    If Application.WorksheetFunction.CountIf(Sheets("COMPARATIF").Range("C:C"), Sheets("AFFRETEMENTS EN COURS").Range("T" & t)) = 0 Then

        If Sheets("AFFRETEMENTS EN COURS").Range("V" & t) = "Affrété & faxé" Then

            x = x + 1

            Sheets("COMPARATIF").Range("A" & x) = Sheets("AFFRETEMENTS EN COURS").Range("B" & t) 'client
            Sheets("COMPARATIF").Range("C" & x) = Sheets("AFFRETEMENTS EN COURS").Range("T" & t) 'Numéro d'OT
            Sheets("COMPARATIF").Range("E" & x) = Sheets("AFFRETEMENTS EN COURS").Range("S" & t) 'Référence client
            Sheets("COMPARATIF").Range("F" & x) = Sheets("AFFRETEMENTS EN COURS").Range("I" & t) 'Date de chargement
            Sheets("COMPARATIF").Range("G" & x) = Sheets("AFFRETEMENTS EN COURS").Range("D" & t) 'Ville de chargement
            Sheets("COMPARATIF").Range("K" & x) = Sheets("AFFRETEMENTS EN COURS").Range("F" & t) 'Ville d'arrivée
            Sheets("COMPARATIF").Range("M" & x) = Sheets("AFFRETEMENTS EN COURS").Range("J" & t) 'Date de livraison
            Sheets("COMPARATIF").Range("N" & x) = Sheets("AFFRETEMENTS EN COURS").Range("K" & t) 'Prix client
            Sheets("COMPARATIF").Range("O" & x) = Sheets("AFFRETEMENTS EN COURS").Range("L" & t) 'Prix affrété
            Sheets("COMPARATIF").Range("P" & x) = Sheets("AFFRETEMENTS EN COURS").Range("M" & t) 'Marge
            Sheets("COMPARATIF").Range("Q" & x) = Sheets("AFFRETEMENTS EN COURS").Range("P" & t) 'Affrété
            Sheets("COMPARATIF").Range("R" & x) = "L'OT ne figure pas dans AKANEA"
            Sheets("COMPARATIF").Range("A" & x & ":Z" & x).Interior.Color = RGB(255, 192, 0)

            Erreur_mois = True


        End If

    End If

Next t


'**********************If rows columns T and C are the same, then we will compare 2 other columns********************************************


For n = 3 To DL_AFFRETEMENT

For t = 2 To DL_COMPARATIF

' Si les OT sont les mêmes

If CStr(Sheets("AFFRETEMENTS EN COURS").Range("T" & n).Value) = CStr(Sheets("COMPARATIF").Range("C" & t).Value) Then

' Alors on verifie que les prix correspondent et si pas correspondance on relève les colonnes + message et calcul de différence

    If CStr(Sheets("AFFRETEMENTS EN COURS").Range("K" & n).Value) <> CStr(Sheets("COMPARATIF").Range("N" & t).Value) Then

        x = x + 1

        For k = 1 To 17

            Sheets("COMPARATIF").Cells(x, k) = Sheets("COMPARATIF").Cells(t, k)

        Next

        Sheets("COMPARATIF").Range("R" & x) = "Ecart de prix client"

        Sheets("COMPARATIF").Range("S" & x) = Sheets("AFFRETEMENTS EN COURS").Range("K" & n) - Sheets("COMPARATIF").Range("N" & t)

        Sheets("COMPARATIF").Range("A" & x & ":S" & x).Interior.Color = RGB(169, 208, 142)

        Erreur_mois = True

    End If

    If CStr(Sheets("AFFRETEMENTS EN COURS").Range("L" & n).Value) <> CStr(Sheets("COMPARATIF").Range("O" & t).Value) Then

        x = x + 1

        For k = 1 To 17

            Sheets("COMPARATIF").Cells(x, k) = Sheets("COMPARATIF").Cells(t, k)

        Next

        Sheets("COMPARATIF").Range("R" & x) = "Ecart de prix affrété"

        Sheets("COMPARATIF").Range("S" & x) = Sheets("AFFRETEMENTS EN COURS").Range("L" & n) - Sheets("COMPARATIF").Range("O" & t)

        Sheets("COMPARATIF").Range("A" & x & ":S" & x).Interior.Color = RGB(47, 117, 181)

        Erreur_mois = True

    End If

End If

Next t

Next n

Заранее благодарим за вашу драгоценную помощь.

1 Ответ

1 голос
/ 26 февраля 2020

Нет хитрости, только волхвы c из объектов словаря .

Option Explicit  
Sub process()

    ' matching cols
    Const col_CMP = "C"
    Const col_AFF = "T" ' Num?ro d'OT

    Dim wb As Workbook, wsAFF As Worksheet, wsCMP As Worksheet, count As Long
    Dim dictAFF As Object, dictCMP As Object
    Dim DL_COMPARATIF As Long, DL_AFFRETEMENT As Long, iRowCMP As Long, iRowAFF As Long
    Dim sKey As String, x As Long, Erreur_mois As Boolean
    Dim t0 As Single
    t0 = Timer

    ' configure
    Set wb = ThisWorkbook
    Set wsAFF = wb.Sheets("AFFRETEMENTS EN COURS") ' Current charters
    Set wsCMP = wb.Sheets("COMPARATIF") ' Comparative

    ' last rows
    DL_COMPARATIF = wsCMP.Range(col_CMP & Rows.count).End(xlUp).Row
    DL_AFFRETEMENT = wsAFF.Range(col_AFF & Rows.count).End(xlUp).Row

    ' build a lookup to CMP
    Set dictCMP = BuildLookup(wsCMP, col_CMP, 2, DL_COMPARATIF)

    ' build a lookup to AFF
    Set dictAFF = BuildLookup(wsAFF, col_AFF, 3, DL_AFFRETEMENT)

    ' scan COMPARATIF for no match with AFFRETEMENT
    count = 0
    Erreur_mois = False
    x = DL_COMPARATIF + 4
    For iRowCMP = 2 To DL_COMPARATIF
         sKey = wsCMP.Range(col_CMP & iRowCMP).Value
         sKey = Trim(sKey)

         If Not dictAFF.exists(sKey) Then
            count = count + 1
            x = x + 1
            wsCMP.Range("A" & x).Resize(1, 17) = wsCMP.Range("A" & iRowCMP).Resize(1, 17).Value
            wsCMP.Range("R" & x) = "L'OT ne figure pas dans Excel." ' does not appear in excel
            wsCMP.Range("A" & x & ":S" & x).Interior.Color = RGB(221, 235, 247) ' pale blue
            Erreur_mois = True
            ' no match remove
            If dictCMP.exists(sKey) Then dictCMP.Remove sKey
         End If
    Next

    MsgBox "Scanned " & wsCMP.Name & " Col " & col_CMP & " to row " & DL_COMPARATIF _
           & vbCr & "Match = " & dictCMP.count _
           & vbCr & "No Match = " & count, vbInformation, "Compare " & wsCMP.Name & " to " & wsAFF.Name

    ' scan AFFRETEMENT for no match with COMPARATIF
    count = 0
    For iRowAFF = 3 To DL_AFFRETEMENT
        sKey = wsAFF.Range(col_AFF & iRowAFF).Value
        sKey = Trim(sKey)

        If Not dictCMP.exists(sKey) Then
            count = count + 1

            If wsAFF.Range("V" & iRowAFF) = "Affrété & faxé" Then ' chartered and faxed
                x = x + 1
                With wsCMP
                    .Range("A" & x) = wsAFF.Range("B" & iRowAFF) 'client
                    .Range("C" & x) = wsAFF.Range("T" & iRowAFF) 'Num?ro d'OT
                    .Range("E" & x) = wsAFF.Range("S" & iRowAFF) 'R?f?rence client
                    .Range("F" & x) = wsAFF.Range("I" & iRowAFF) 'Date de chargement
                    .Range("G" & x) = wsAFF.Range("D" & iRowAFF) 'Ville de chargement
                    .Range("K" & x) = wsAFF.Range("F" & iRowAFF) 'Ville d'arriv?e
                    .Range("M" & x) = wsAFF.Range("J" & iRowAFF) 'Date de livraison
                    .Range("N" & x) = wsAFF.Range("K" & iRowAFF) 'Prix client
                    .Range("O" & x) = wsAFF.Range("L" & iRowAFF) 'Prix affr?t?
                    .Range("P" & x) = wsAFF.Range("M" & iRowAFF) 'Marge
                    .Range("Q" & x) = wsAFF.Range("P" & iRowAFF) 'Affr?t?
                    .Range("R" & x) = "L'OT ne figure pas dans AKANEA"
                    .Range("A" & x & ":Z" & x).Interior.Color = RGB(255, 192, 0) ' yellow
                End With
                Erreur_mois = True
            End If

            ' no match remove
            If dictAFF.exists(sKey) Then dictAFF.Remove sKey
         End If
    Next

    MsgBox "Scanned " & wsAFF.Name & " Col " & col_AFF & " to row " & DL_AFFRETEMENT _
           & vbCr & "Match = " & dictAFF.count _
           & vbCr & "No Match = " & count, vbInformation, "Compare " & wsAFF.Name & " to " & wsCMP.Name

    MsgBox "Items matched dictAFF=" & dictAFF.count & " dictCMP=" & dictCMP.count, vbInformation, "Matched"

    ' compare prices for matching records
    Dim diffA As Single, diffC As Single, OT As Variant
    count = 1
    For Each OT In dictAFF.keys

        ' Alors on verifie que les prix correspondent et si pas
        ' correspondance on rel?ve les colonnes + message et calcul de diff?rence
        ' So we check that the prices match and if not match
        ' we pick up the columns + message and difference calculation
        iRowAFF = dictAFF.Item(OT)
        iRowCMP = dictCMP.Item(OT)
        'Debug.Print "Match " & OT & " AFF Row=" & iRowAFF & " CMP=" & iRowCMP

        ' calc Customer price difference
        diffC = wsAFF.Range("K" & iRowAFF).Value - wsCMP.Range("N" & iRowCMP).Value
        If Abs(diffC) > 0 Then
            x = x + 1
            wsCMP.Range("A" & x).Resize(1, 17) = wsCMP.Range("A" & iRowAFF).Resize(1, 17).Value
            wsCMP.Range("R" & x) = "Ecart de prix client" ' Customer price difference
            wsCMP.Range("S" & x) = Round(diffC, 3)
            wsCMP.Range("A" & x & ":S" & x).Interior.Color = RGB(169, 208, 142) ' green
            Erreur_mois = True
        End If

        ' calc Charter price difference
        diffA = wsAFF.Range("L" & iRowAFF).Value - wsCMP.Range("O" & iRowCMP).Value
        If Abs(diffA) > 0 Then
            x = x + 1
            wsCMP.Range("A" & x).Resize(1, 17) = wsCMP.Range("A" & iRowAFF).Resize(1, 17).Value
            wsCMP.Range("R" & x) = "Ecart de prix affr?t?" ' Charter price difference
            wsCMP.Range("S" & x) = Round(diffA, 3)
            wsCMP.Range("A" & x & ":S" & x).Interior.Color = RGB(47, 117, 181) 'blue
            Erreur_mois = True ' error month
        End If

    Next
    MsgBox "Completed in " & Int(Timer = t0) & " seconds", vbInformation, "Complete"

End Sub

Function BuildLookup(ByRef ws As Worksheet, col As String, firstrow As Long, lastrow As Long) As Object

    Dim dict As Object, i As Long, sKey As String, t0 As Single
    t0 = Timer
    Set dict = CreateObject("Scripting.Dictionary")
    For i = firstrow To lastrow
         sKey = ws.Range(col & i).Value
         sKey = Trim(sKey)
         If Len(sKey) > 0 Then
            If dict.exists(sKey) Then
                MsgBox "Duplicate key '" & sKey & "' at row " & i, vbExclamation, "ERROR in col " & col & " " & ws.Name
            Else
                dict.Add sKey, i
            End If
        End If
    Next
    Set BuildLookup = dict

    MsgBox "Scanned Column " & col & " Rows " & firstrow & " to " & lastrow, _
           vbInformation, ws.Name & " Dictionary built in " & Int(Timer - t0) & " seconds"

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