this code become slow for 18000 rows despite of using dictionary and array

leap out

Active Member
Joined
Dec 4, 2020
Messages
288
Office Version
  1. 2016
  2. 2010
Hi experts
I got help from mr.Peter_Ss with some modification .
the code becomes more slowly when test for big data, despite of using dictionary & array
so the big data can be 18000 rows for each sheet . the code will calculation items based on column B and if there is duplicates items should merge for each sheet . the formula will be (stock-sales+pur-return) in sheet summary for last column ,also if there is new item in one of sheets but is not in another , then should also show and calculation . the code create whole data with format & borders and collect the data across sheet into sheet summary
VBA Code:
Sub CollateData_v4()
  Dim d As Object
  Dim ShList As Variant, a As Variant, vals As Variant
  Dim i As Long, j As Long
  Dim s As String
 
  Set d = CreateObject("Scripting.Dictionary")
  ShList = Split("stock|sales|pur|returns", "|")
  For j = 0 To UBound(ShList)
    With Sheets(ShList(j))
      a = .UsedRange.Value2
      For i = 2 To UBound(a)
        s = .Cells(i, 2)
        If Len(s) > 2 Then
         
        If Not d.exists(s) Then d(s) = Join(Application.Index(a, i, Array(3, 4, 5)), ";") & ";;;;"
          vals = Split(d(s), ";")
          If IsNumeric(vals(j + 3)) Then
           vals(j + 3) = vals(j + 3) + a(i, 6)
           Else
           vals(j + 3) = a(i, 6)
          End If
         
            d(s) = Join(vals, ";")
         
        End If
      Next i
    End With
  Next j
  Application.ScreenUpdating = False
  With Sheets("summary")
    .UsedRange.EntireRow.Delete
    With .Range("B2:C2").Resize(d.Count)
      .Value = Application.Transpose(Array(d.Keys, d.Items))
      With .Columns(2)
        .TextToColumns DataType:=xlDelimited, ConsecutiveDelimiter:=False, Semicolon:=True, Comma:=False, Space:=False, Other:=False
        With .Offset(, 7) ' ### was .Offset(, 5)
          .FormulaR1C1 = "=RC[-4]-RC[-3]+RC[-2]+RC[-1]"
          .Value = .Value
        End With
        '.Resize(, 3).EntireColumn.Insert '### not needed
      End With
      .Columns(1).TextToColumns DataType:=xlDelimited, ConsecutiveDelimiter:=False, Semicolon:=True, Comma:=False, Space:=False, Other:=False
      With .Columns(0)
        .Cells(1).Value = 1
        .DataSeries Rowcol:=xlColumns, Type:=xlLinear, Step:=1
      End With
    End With
    With .Range("A1:J1")
      .Value = Array("item", "CODE", "BRAND", "TYPE", "MANUFACTURE", "STOCK", "SALES", "PUR", "RETURNS", "BALANCE")
       .Font.Bold = True
  .Interior.Color = RGB(166, 166, 166)
      .EntireColumn.AutoFit
    End With
    With .UsedRange
      .BorderAround xlContinuous
      .Borders(xlInsideVertical).LineStyle = xlContinuous
      .Borders(xlInsideHorizontal).LineStyle = xlContinuous
    End With
  End With
  Application.ScreenUpdating = True
End Sub
for more detailes
INVEN with single search v0 c.xlsm
ABCDEF
1itemCODEBRANDTYPEMANUFACTUREQTY
21AA-110W40 208LQ8EU2222
32AA-215W40 208LCASSU400
43AA-35W30 208LQ8EU800
54AA-45W30 12x1LQ8EU600
65AA-510W40 208LENIIT300
76AA-65W30 4x4LQ8EU200
87AA-710W40 12x1LQ8EU120
98AA-815W40 12x1LCASSU450
109AA-910W40 12x1LENIIT890
1110AA-1010W40 4x4LQ8EU345
1211AA-1110W40 4x4LCASSU78
1312AA-1210W40 4x4LENIIT123
1413AA-135W40 4x4LQ8EU456
1514AA-145W40 4x4LCASSU678
1615AA-155W40 4x4LENIIT1234
1716AA-1620W50 4x4LQ8EU456
stock



INVEN with single search v0 c.xlsm
ABCDEF
1DATECODEBRANDTYPEMANUFACTURESALES
21/1/2021AA-110W40 208LQ8EU100
31/2/2021AA-215W40 208LCASSU50
41/3/2021AA-35W30 208LQ8EU280
51/4/2021AA-45W30 12x1LQ8EU300
61/5/2021AA-510W40 208LENIIT80
71/6/2021AA-65W30 4x4LQ8EU20
81/7/2021AA-710W40 12x1LQ8EU20
91/8/2021AA-815W40 12x1LCASSU20
101/9/2021AA-910W40 12x1LENIIT876
111/10/2021AA-1010W40 4x4LQ8EU345
121/11/2021AA-1110W40 4x4LCASSU123
131/12/2021AA-1210W40 4x4LENIIT78
141/13/2021AA-135W40 4x4LQ8EU300
151/14/2021AA-145W40 4x4LCASSU34
161/15/2021AA-155W40 4x4LENIIT23
171/16/2021AA-1620W50 4x4LQ8EU56
181/17/2021AA-110W40 208LQ8EU100
sales



INVEN with single search v0 c.xlsm
ABCDEF
1DATECODEBRANDTYPEMANUFACTUREPURCHASE
22/4/2021AA-110W40 208LQ8EU55
32/5/2021AA-215W40 208LCASSU20
42/6/2021AA-35W30 208LQ8EU10
52/7/2021AA-45W30 12x1LQ8EU10
62/8/2021AA-510W40 208LENIIT3
72/9/2021AA-65W30 4x4LQ8EU4
82/10/2021AA-710W40 12x1LQ8EU45
92/11/2021AA-815W40 12x1LCASSU8
102/12/2021AA-910W40 12x1LENIIT1
112/13/2021AA-1010W40 4x4LQ8EU100
122/14/2021AA-1110W40 4x4LCASSU20
132/15/2021AA-1210W40 4x4LENIIT100
142/16/2021AA-135W40 4x4LQ8EU44
152/17/2021AA-145W40 4x4LCASSU20
162/18/2021AA-155W40 4x4LENIIT50
172/19/2021AA-1620W50 4x4LQ8EU12
182/20/2021AA-1720W50 4x4LCASSU9
192/21/2021AA-1820W50 4x4LENIIT4
202/22/2021AA-110W40 208LQ8EU55
pur


INVEN with single search v0 c.xlsm
ABCDEF
1itemCODEBRANDTYPEMANUFACTUREreturns
24/5/2021AA-910W40 12x1LENIIT20
34/6/2021AA-1010W40 4x4LQ8EU30
44/7/2021AA-1110W40 4x4LCASSU40
54/8/2021AA-45W30 12x1LQ8EU10
64/9/2021AA-45W30 12x1LQ8EU11
returns



result
INVEN with single search v0 c.xlsm
ABCDEFGHIJ
1itemCODEBRANDTYPEMANUFACTURESTOCKSALESPURRETURNSBALANCE
21AA-110W40 208LQ8EU22222001102132
32AA-215W40 208LCASSU4005020370
43AA-35W30 208LQ8EU80028010530
54AA-45W30 12x1LQ8EU6003001021331
65AA-510W40 208LENIIT300803223
76AA-65W30 4x4LQ8EU200204184
87AA-710W40 12x1LQ8EU1202045145
98AA-815W40 12x1LCASSU450208438
109AA-910W40 12x1LENIIT89087612035
1110AA-1010W40 4x4LQ8EU34534510030130
1211AA-1110W40 4x4LCASSU78123204015
1312AA-1210W40 4x4LENIIT12378100145
1413AA-135W40 4x4LQ8EU45630044200
1514AA-145W40 4x4LCASSU6783420664
1615AA-155W40 4x4LENIIT123423501261
1716AA-1620W50 4x4LQ8EU4565612412
1817AA-1720W50 4x4LCASSU99
1918AA-1820W50 4x4LENIIT44
summary

can anybody make it fast,please?
 

Excel Facts

Move date out one month or year
Use =EDATE(A2,1) for one month later. Use EDATE(A2,12) for one year later.
change this line:
VBA Code:
s = .Cells(i, 2)
to
VBA Code:
s=a(i,2)
Note this does assume your used range starts at cell A1, if it doesn't there are ways round it.
 
Upvote 0
thanks for your suggestion, but unfortunately still too slow . it gives 42.40 sec when I test it .:rolleyes:
 
Upvote 0
Your code has a lot of lines where you are splitting up the value of the dictionary to then add a number to the final part of the dictionary value and then joning it back up again. I don't think you need to do this. My idea is to make the dictionary key the concatenation of all of column B,C , D and E, the dictinalry vlaue is then just the count . Then it is very easy to add in the extra stock without splitting and joining. Like this:
VBA Code:
  Set d = CreateObject("Scripting.Dictionary")
  ShList = Split("stock|sales|pur|returns", "|")
  For j = 0 To UBound(ShList)
    With Sheets(ShList(j))
      a = .UsedRange.Value2
      For i = 2 To UBound(a)
        s = a(i, 2) & a(i, 3) & a(i, 4) & a(i5)   ' contcatenate beforee adding to dictionary
        If Len(a(i, 2)) > 2 Then
         
          If Not d.exists(s) Then
            d.Add s, a(i, 6)
          Else
            d(s) = d(s) + a(i, 6)
          End If
        End If
      Next i
    End With
  Next j
 
Upvote 0
thanks but the showing of data are incorrect
this is what I got
INVEN with single search v0 c.xlsm
ABCDEFGHIJ
1itemCODEBRANDTYPEMANUFACTURESTOCKSALESPURRETURNSBALANCE
21AA-110W40 208LQ8EU21320
32AA-215W40 208LCASSU3700
43AA-35W30 208LQ8EU5300
54AA-45W30 12x1LQ8EU3310
65AA-510W40 208LENIIT2230
76AA-65W30 4x4LQ8EU1840
87AA-710W40 12x1LQ8EU1450
98AA-815W40 12x1LCASSU4380
109AA-910W40 12x1LENIIT350
1110AA-1010W40 4x4LQ8EU1300
1211AA-1110W40 4x4LCASSU150
1312AA-1210W40 4x4LENIIT1450
1413AA-135W40 4x4LQ8EU2000
1514AA-145W40 4x4LCASSU6640
1615AA-155W40 4x4LENIIT12610
1716AA-1620W50 4x4LQ8EU4120
1817AA-1710W40 4x4LCASSU90
1918AA-1810W40 4x4LENIIT40
summary
 
Upvote 0
@leap out, Because of your question, I have decided to try and learn how dictionaries work. I am familiar with arrays, but dictionaries are a bit different. Once I wrap my head around the idea, I will post back here, with hopefully a solution you can test.
 
Upvote 0
Hope it works:
VBA Code:
Option Explicit
Sub test()
Dim lr&, i&, k&, rng, arr(), ws, Val, id As String
Dim dic As Object, key
Set dic = CreateObject("Scripting.Dictionary")
ws = Array("stock", "sales", "pur", "returns")
For k = 1 To UBound(ws) + 1
    With Worksheets(ws(k - 1))
        lr = .Cells(Rows.Count, "B").End(xlUp).Row
        rng = .Range("A2:F" & lr).Value2
        For i = 1 To lr - 1
            id = rng(i, 2) & "|" & rng(i, 3) & "|" & rng(i, 4) & "|" & rng(i, 5)
            If Not dic.exists(id) Then
                Val = Array(0, 0, 0, 0)
                Val(k - 1) = rng(i, 6)
                dic.Add id, Val
            Else
                Val = dic(id)
                Val(k - 1) = Val(k - 1) + rng(i, 6)
                dic(id) = Val
            End If
        Next
    End With
Next
ReDim arr(1 To dic.Count, 1 To 10)
k = 0
For Each key In dic.keys
    k = k + 1: arr(k, 1) = k
    For i = 0 To 3
        arr(k, i + 2) = Split(key, "|")(i)
    Next
    For i = 0 To 3
        arr(k, i + 6) = dic(key)(i)
    Next
    arr(k, 10) = arr(k, 6) - arr(k, 7) + arr(k, 8) + arr(k, 9)
Next
With Worksheets("summary")
    .Range("A2:J10000").ClearContents
    .Range("A2").Resize(UBound(arr), 10).Value = arr
End With
End Sub
 
Upvote 0
@leap out, Because of your question, I have decided to try and learn how dictionaries work. I am familiar with arrays, but dictionaries are a bit different. Once I wrap my head around the idea, I will post back here, with hopefully a solution you can test.

Here is what I came up with:

VBA Code:
Sub CollateData_v5()
'
'   This requires creating a new class Module that you will name 'AF_DictionaryClass'
'
'       In that Class Module type the following:
'    Public ThisCode         As String       ' Code ... Key
'
'    Public ThisBrand        As String       ' Brand ... Item
'    Public ThisType         As String       ' Type ... Item
'    Public ThisManufacture  As String       ' Manufacture ... Item
'    Public ThisStock        As Long         ' stock ... Item
'    Public ThisSales        As Long         ' sales ... Item
'    Public ThisPur          As Long         ' pur ... Item
'    Public ThisReturns      As Long         ' returns ... Item
'
'       That will establish the key and 7 items for the key, make sure you Dim them properly. ;)
'
    Dim StartTime           As Double
    StartTime = Timer                                                                   ' Start the stopwatch
'
    Dim ArrayFreeDictionary As AF_DictionaryClass
    Dim ElapsedTime         As Double
    Dim ArrayRow            As Long
    Dim CodeColumn          As Long, BrandColumn        As Long, TypeColumn As Long
    Dim ManufactureColumn   As Long, QuantityColumn     As Long
    Dim StartRow            As Long, LastRow            As Long
    Dim SheetName           As Long
    Dim TheDictionary       As Object
    Dim ThisCode            As String
    Dim key                 As Variant
    Dim OutputArray         As Variant
    Dim SheetDataArray      As Variant, SheetNameArray  As Variant
    Dim OutputSheet         As Worksheet
'
    StartRow = 2                                                                        ' <--- Set this to the start row of input data and output data
    Set OutputSheet = Sheets("summary")                                                 ' <--- Set this to the sheet name that you display results to
'
    Set TheDictionary = CreateObject("scripting.dictionary")                            ' Create TheDictionary
'
    SheetNameArray = Array("stock", "sales", "pur", "returns")                          ' Add sheet names to SheetNameArray
'
           CodeColumn = 2
          BrandColumn = 3
           TypeColumn = 4
    ManufactureColumn = 5
       QuantityColumn = 6
'
    For SheetName = 0 To UBound(SheetNameArray)                                         ' Loop through sheets in SheetNameArray
        SheetDataArray = Sheets(SheetNameArray(SheetName)).UsedRange.Value2             '   Load data from sheet into SheetDataArray
'
        For ArrayRow = StartRow To UBound(SheetDataArray, 1)                            '   Loop through rows of each sheets data
            ThisCode = SheetDataArray(ArrayRow, CodeColumn)                             '       Save the 'code' into ThisCode
'
            If TheDictionary.Exists(ThisCode) Then                                      '       If the 'code' has already been added then ...
                Set ArrayFreeDictionary = TheDictionary(ThisCode)                       '
            Else                                                                        '       Else ...
                Set ArrayFreeDictionary = New AF_DictionaryClass                        '       Create a new AF_DictionaryClass object
'
                TheDictionary.Add ThisCode, ArrayFreeDictionary                         '       Add the 'code' & new AF_DictionaryClass object to
'                                                                                       '               the dictionary
            End If
'
                  ArrayFreeDictionary.ThisBrand = SheetDataArray(ArrayRow, BrandColumn) '       Add Brand to ArrayFreeDictionary.ThisBrand
                   ArrayFreeDictionary.ThisType = SheetDataArray(ArrayRow, TypeColumn)  '       Add Type to ArrayFreeDictionary.ThisType
            ArrayFreeDictionary.ThisManufacture = SheetDataArray(ArrayRow, ManufactureColumn)   '       Add Manufacture to ArrayFreeDictionary.ThisManufacture
'
            Select Case SheetName
                Case 0: ArrayFreeDictionary.ThisStock = SheetDataArray(ArrayRow, QuantityColumn) _
                        + ArrayFreeDictionary.ThisStock                                 '           Add quantity to ArrayFreeDictionary.ThisStock
                Case 1: ArrayFreeDictionary.ThisSales = SheetDataArray(ArrayRow, QuantityColumn) _
                        + ArrayFreeDictionary.ThisSales                                 '           Add quantity to ArrayFreeDictionary.ThisSales
                Case 2: ArrayFreeDictionary.ThisPur = SheetDataArray(ArrayRow, QuantityColumn) _
                        + ArrayFreeDictionary.ThisPur                                   '           Add quantity to ArrayFreeDictionary.ThisPur
                Case 3: ArrayFreeDictionary.ThisReturns = SheetDataArray(ArrayRow, QuantityColumn) _
                        + ArrayFreeDictionary.ThisReturns                               '           Add quantity to ArrayFreeDictionary.ThisReturns
            End Select
        Next                                                                            '   Loop back
    Next                                                                                ' Loop back
'
'----------------------------------------------------------
'
' Write the Dictionary contents to an array
'
    ReDim OutputArray(1 To TheDictionary.Count, 1 To 9)
'
    ArrayRow = 1                                                                        ' Initialize ArrayRow
'
    For Each key In TheDictionary.Keys                                                  ' Loop through keys in TheDictionary
        Set ArrayFreeDictionary = TheDictionary(key)
'
        With ArrayFreeDictionary
            OutputArray(ArrayRow, 1) = ArrayRow
            OutputArray(ArrayRow, 2) = key                                              '       Write the contents of TheDictionary to OutputArray
            OutputArray(ArrayRow, 3) = .ThisBrand
            OutputArray(ArrayRow, 4) = .ThisType
            OutputArray(ArrayRow, 5) = .ThisManufacture
            OutputArray(ArrayRow, 6) = .ThisStock
            OutputArray(ArrayRow, 7) = .ThisSales
            OutputArray(ArrayRow, 8) = .ThisPur
            OutputArray(ArrayRow, 9) = .ThisReturns
'
            ArrayRow = ArrayRow + 1                                                     '       Increment ArrayRow
        End With
    Next                                                                                ' Loop back
'
'----------------------------------------------------------
'
' Write the array to worksheet
    With OutputSheet
        .UsedRange.ClearContents                                                        '   Delete all existing data from the OutputSheet
'
        .Range("A2").Resize(UBound(OutputArray, 1), UBound(OutputArray, 2)) = OutputArray   '   Display OutputArray to OutputSheet
'
        With .Range("A1:J1")
            .Value = Array("item", "CODE", "BRAND", "TYPE", "MANUFACTURE", "STOCK", _
                    "SALES", "PUR", "RETURNS", "BALANCE")                               '       Display Headers to OutputSheet
            .Font.Bold = True                                                           '       Bold the Headers
            .Interior.Color = RGB(166, 166, 166)                                        '       Fill the cells of the Headers with a color
            .EntireColumn.AutoFit                                                       '       Size the columns to autofit
        End With
'
        LastRow = .Range("B" & Rows.Count).End(xlUp).row                                '   Get last used row in OutputSheet
'
        .UsedRange.NumberFormat = "0;-0;;@"                                             '   Format the cells of the OutputSheet to hide zero values
'
        With .Range("J2:J" & LastRow)
            .Value = OutputSheet.Evaluate(.Offset(0, -4).Address & "-" & _
                    .Offset(0, -3).Address & "+" & .Offset(0, -2).Address & _
                    "+" & .Offset(0, -1).Address)                                       '       Use formula to calculate 'Balance' column values
        End With
    End With
'
'----------------------------------------------------------
'
    ElapsedTime = Timer - StartTime                                                     ' Save ElapsedTime
    Debug.Print "Time to complete operation was " & ElapsedTime & " seconds."           ' Display elapsed time to 'Immediate' window (CTRL+G) in VBE
    MsgBox "Time to complete operation was " & ElapsedTime & " seconds."                ' Display elapsed time to message box
End Sub
 
Upvote 0
To keep everything within the dictionary. Should be very fast

VBA Code:
Sub jec()
 Dim sp, ar, k, a, j As Long, jj As Long, x As Long
 sp = Split("stock|sales|pur|returns", "|")
  
 With CreateObject("scripting.dictionary")
    For j = 0 To UBound(sp)
       ar = Sheets(sp(j)).UsedRange
       For jj = 2 To UBound(ar)
         k = ar(jj, 3) & "|" & ar(jj, 4) & "|" & ar(jj, 5)
         If Not .exists(k) Then
           .Item(k) = Array(x + 1, ar(jj, 2), ar(jj, 3), ar(jj, 4), ar(jj, 5), 0, 0, 0, 0, 0)
           a = .Item(k)
           a(j + 5) = ar(jj, 6)
           a(9) = ar(jj, 6)
           x = x + 1
         Else
           a = .Item(k)
           a(j + 5) = a(j + 5) + ar(jj, 6)
           a(9) = a(9) + IIf(j = 1, -ar(jj, 6), ar(jj, 6))
         End If
         .Item(k) = a
       Next
    Next
    Sheets("summary").Range("A2").Resize(.Count, 10) = Application.Index(.items, 0, 0)
 End With
End Sub
 
Last edited:
Upvote 0
Could not change it anymore, here a version with one less variable :)

VBA Code:
Sub jec()
 Dim sp, ar, k, a, j As Long, jj As Long
 sp = Split("stock|sales|pur|returns", "|")
 
 With CreateObject("scripting.dictionary")
    For j = 0 To UBound(sp)
       ar = Sheets(sp(j)).UsedRange
       For jj = 2 To UBound(ar)
         k = ar(jj, 3) & "|" & ar(jj, 4) & "|" & ar(jj, 5)
         If Not .exists(k) Then
           .Item(k) = Array(.Count + 1, ar(jj, 2), ar(jj, 3), ar(jj, 4), ar(jj, 5), 0, 0, 0, 0, 0)
           a = .Item(k)
           a(j + 5) = ar(jj, 6)
           a(9) = ar(jj, 6)
         Else
           a = .Item(k)
           a(j + 5) = a(j + 5) + ar(jj, 6)
           a(9) = a(9) + IIf(j = 1, -ar(jj, 6), ar(jj, 6))
         End If
         .Item(k) = a
       Next
    Next
    Sheets("summary").Range("A2").Resize(.Count, 10) = Application.Index(.items, 0, 0)
 End With
End Sub
 
Upvote 0

Forum statistics

Threads
1,223,246
Messages
6,170,996
Members
452,373
Latest member
TimReeks

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top