Make a new VBA faster

motilulla

Well-known Member
Joined
Feb 13, 2008
Messages
2,362
Office Version
  1. 2010
Using Excel 2010
Hello,

Here is example with 65 rows in the range B6:O10500 I have a set of combinations and in the range U6:AH4500 I have a set of results. (I want to check all the result against all combinations)

For that I am using formula in cell Q6 below. And the below VBA give me the results in cell R6 Below.

The problem when there is combination with 10500 rows and results with 4500 rows it is taking too much time to populate the results.

Please I need a help is there any fast VBA version to solve this issue.

Here is below the example sheet with formula and VBA which I am using are attached.

MrExcel.xlsm
ABCDEFGHIJKLMNOPQRSTUVWXYZAAABACADAEAFAGAH
1
2
3
4105004500
5CombiP1P2P3P4P5P6P7P8P9P10P11P12P13P14Results Checked With FormulaResults Checked With VBAResultP1P2P3P4P5P6P7P8P9P10P11P12P13P14
61112111111111111414111211111111111
721121111111111X13132112111111111XX
8311211111111112131331121111111X11X
94112111111111X1131341121111111X1X1
105112111111111XX14145112111111X111X
116112111111111X213136112111111X11X1
1271121111111X11113137112111111XX111
1381121111111X11X14148112111111XX1XX
1491121111111X1121313911211111121112
15101121111111X1X11414101121111112X1X2
16111121111111X1XX13131111211111X1111X
17121121111111X1X213131211211111X111X1
1813112111111X111113131311211111X1X111
1914112111111X111X14141411211111X1X1XX
2015112111111X111213131511211111XX1111
2116112111111X11X114141611211111XX11XX
2217112111111X11XX13131711211111XXX11X
2318112111111X11X213131811211111XXX1X1
2419112111111XX11114141911211111X211X2
2520112111111XX11X13132011211111X2X112
2621112111111XX11213132111211111211112
2722112111111XX1X11313221121111121X1X2
2823112111111XX1XX141423112111112X11X2
2924112111111XX1X2131324112111112XX112
30251121111112111113132511211111221111
31261121111112111X131326112111112211XX
322711211111121112141427
3328112111111211X1131328
3429112111111211XX131329
3530112111111211X2131330
36311121111112X111131331
37321121111112X11X131332
38331121111112X112131333
39341121111112X1X1131334
40351121111112X1XX131335
41361121111112X1X2141436
423711211111X11111131337
433811211111X1111X141438
443911211111X11112131339
454011211111X111X1141440
464111211111X111XX131341
474211211111X111X2131342
484311211111X1X111141443
494411211111X1X11X131344
504511211111X1X112131345
514611211111X1X1X1131346
524711211111X1X1XX141447
534811211111X1X1X2131348
544911211111XX1111141449
555011211111XX111X131350
565111211111XX1112131351
575211211111XX11X1131352
585311211111XX11XX141453
595411211111XX11X2131354
605511211111XXX111131355
615611211111XXX11X141456
625711211111XXX112131357
635811211111XXX1X1141458
645911211111XXX1XX131359
656011211111XXX1X2131360
Check Results
Cell Formulas
RangeFormula
Q6:Q65Q6=MAX(MMULT(--($U$6:$AH$20000=B6:O6),TRANSPOSE(COLUMN($U$6:$AH$6))^0))
Press CTRL+SHIFT+ENTER to enter array formulas.


VBA Code:
Sub Formula_InTo_VBA()
Dim a, b, c
Dim i As Long, j As Long, k As Long, n As Long

Range("R6:R20000").ClearContents

Application.ScreenUpdating = False

Lr = Cells(Rows.Count, "B").End(xlUp).Row
a = Range("B6:O" & Lr)
ReDim c(1 To Lr)
Lr = Cells(Rows.Count, "U").End(xlUp).Row
b = Range("U6:AH" & Lr)

For i = 1 To UBound(a, 1)
    xmax = 0
    For j = 1 To UBound(b, 1)
        n = 0
        For k = 1 To 14
            If a(i, k) = b(j, k) Then n = n + 1
        Next k
        xmax = Application.Max(xmax, n)
        Next j
  
    c(i) = xmax
Next i

[R6].Resize(UBound(c, 1), 1) = Application.Transpose(c)

Application.ScreenUpdating = True

End Sub

Regards,
Moti
 
You should know better than this.
Please provide the link to all & any crossposts.
Hello Fluff, I am sorry, sure here is below the link to cross post.
Please need help to rewrite the VBA

Please anyone can download the file from link above to make a VBA result faster.

Here rlv01, has helped in the post#2 after replacing those lines VBA has reduced significant time but according to rlv01 it need to rewrite for further improvement. Please Help

Regards,
Moti
 
Upvote 0

Excel Facts

Formula for Yesterday
Name Manager, New Name. Yesterday =TODAY()-1. OK. Then, use =YESTERDAY in any cell. Tomorrow could be =TODAY()+1.
See if this helps:
(It is based on your file which has the results column starting at S and not T)

VBA Code:
Sub Formula_InTo_VBA()
    Dim startTime As Double
    startTime = Timer
   
    Dim a, b, c
    Dim i As Long, j As Long, k As Long, n As Long, m As Long
    Dim Lr As Long, xmax As Long
    Dim iPossible As Long, iMiss As Long, xMiss As Long
   
    Range("Q6:Q20000").ClearContents
   
    Application.ScreenUpdating = False
   
    Lr = Cells(Rows.Count, "B").End(xlUp).Row
    a = Range("B6:O" & Lr)
    ReDim c(1 To Lr, 1 To 1)
    Lr = Cells(Rows.Count, "U").End(xlUp).Row
    'b = Range("U6:AH" & Lr)
    b = Range("T6:AG" & Lr)
   
    iPossible = UBound(b)
   
    For i = 1 To UBound(a, 1)
        xmax = 0
        xMiss = iPossible
       
        For j = 1 To UBound(b, 1)
            n = 0
            iMiss = 0
            For k = 1 To 14
                If a(i, k) = b(j, k) Then
                    n = n + 1
                Else
                    ' if more misses than the best so fart no point in looking further
                    iMiss = iMiss + 1
                    If iMiss > xMiss Then Exit For
                End If
            Next k
           
            If n > xmax Then
                xmax = n
                xMiss = iPossible - xmax
            End If
            ' if iPossible is reached no point looking further
            If xmax = iPossible Then Exit For
        Next j
      
        c(i, 1) = xmax
    Next i
    
    Range("Q6").Resize(UBound(c, 1), 1) = c
   
    Application.ScreenUpdating = True
   
    Debug.Print Timer - startTime
     
End Sub
 
Upvote 1
See if this helps:
(It is based on your file which has the results column starting at S and not T)
Hello Alex Blakenburg, It is true results starting from the columns S good catch.

I tried your code with attached file I noticed that it works smooth without making a noise but the result timings are same (with your and attached macro) 00:01:14 Minute. I think you would have tested also.

With attached macro machine were making too noise and I was getting massage excel (No Responding) some time it was getting block too.

I am grateful to you for re-writing a code and it is performing great. (y)

Have a good weekend and Good Luck.

My Best regards,
Moti :)
 
Upvote 0
Hi Moti @motilulla

I spotted an issue with the code I gave you. Please change this line.
and see if it makes a difference.
Rich (BB code):
iPossible = UBound(b)
' it should be
iPossible = UBound(b, 2)


Also I revisited an earlier attempt using an dictionary and by combining it with the code I posted I believe it faster than the previous version.

VBA Code:
Sub Formula_InTo_VBA_Escapev_RngAdj_AddDict()
    Dim startTime As Double
    startTime = Timer
    
    Dim a, b, c
    Dim i As Long, j As Long, k As Long, n As Long, m As Long
    Dim Lr As Long, xmax As Long
    Dim iPossible As Long, iMiss As Long, xMiss As Long
    Dim dicResult As Object, dicKey As String
    
    Range("Q6:Q20000").ClearContents
    
    Application.ScreenUpdating = False
    
    Lr = Cells(Rows.Count, "B").End(xlUp).Row
    a = Range("B6:O" & Lr)
    ReDim c(1 To Lr, 1 To 1)
    Lr = Cells(Rows.Count, "T").End(xlUp).Row 
    b = Range("T6:AG" & Lr)
    
    iPossible = UBound(b, 2)
    
    Set dicResult = CreateObject("Scripting.dictionary")
    dicResult.CompareMode = vbTextCompare
    For i = 1 To UBound(b, 1)
        dicKey = ""
        For j = 1 To UBound(b, 2)
            dicKey = dicKey & "|" & b(i, j)
        Next j
        dicKey = Right(dicKey, Len(dicKey) - 1)
        If Not dicResult.exists(dicKey) Then
            dicResult(dicKey) = i
        End If
    
    Next i

    For i = 1 To UBound(a, 1)
        xmax = 0
        xMiss = iPossible
        
        dicKey = ""
        For m = 1 To UBound(a, 2)
            dicKey = dicKey & "|" & a(i, m)
        Next m
        dicKey = Right(dicKey, Len(dicKey) - 1)
        If Not dicResult.exists(dicKey) Then
          
          For j = 1 To UBound(b, 1)
              n = 0
              iMiss = 0
              For k = 1 To 14
                  If a(i, k) = b(j, k) Then
                      n = n + 1
                  Else
                      ' if more misses than the best so far no point in looking further
                      iMiss = iMiss + 1
                      If iMiss > xMiss Then Exit For
                  End If
              Next k
             
              If n > xmax Then
                  xmax = n
                  xMiss = iPossible - xmax
              End If
              ' if iPossible is reached no point looking further
              ' Shouldn't need this the dictionary lookup so catch it before here
              If xmax = iPossible Then Exit For
          Next j
        Else
            xmax = iPossible
        End If
          c(i, 1) = xmax
    Next i
    
    Range("Q6").Resize(UBound(c, 1), 1) = c
    
    Application.ScreenUpdating = True
    
    Debug.Print Timer - startTime
End Sub
 
Upvote 1
Solution
Hi Moti @motilulla

I spotted an issue with the code I gave you. Please change this line.
and see if it makes a difference.
Rich (BB code):
iPossible = UBound(b)
' it should be
iPossible = UBound(b, 2)


Also I revisited an earlier attempt using an dictionary and by combining it with the code I posted I believe it faster than the previous version.

VBA Code:
Sub Formula_InTo_VBA_Escapev_RngAdj_AddDict()
    Dim startTime As Double
    startTime = Timer
   
    Dim a, b, c
    Dim i As Long, j As Long, k As Long, n As Long, m As Long
    Dim Lr As Long, xmax As Long
    Dim iPossible As Long, iMiss As Long, xMiss As Long
    Dim dicResult As Object, dicKey As String
   
    Range("Q6:Q20000").ClearContents
   
    Application.ScreenUpdating = False
   
    Lr = Cells(Rows.Count, "B").End(xlUp).Row
    a = Range("B6:O" & Lr)
    ReDim c(1 To Lr, 1 To 1)
    Lr = Cells(Rows.Count, "T").End(xlUp).Row
    b = Range("T6:AG" & Lr)
   
    iPossible = UBound(b, 2)
   
    Set dicResult = CreateObject("Scripting.dictionary")
    dicResult.CompareMode = vbTextCompare
    For i = 1 To UBound(b, 1)
        dicKey = ""
        For j = 1 To UBound(b, 2)
            dicKey = dicKey & "|" & b(i, j)
        Next j
        dicKey = Right(dicKey, Len(dicKey) - 1)
        If Not dicResult.exists(dicKey) Then
            dicResult(dicKey) = i
        End If
   
    Next i

    For i = 1 To UBound(a, 1)
        xmax = 0
        xMiss = iPossible
       
        dicKey = ""
        For m = 1 To UBound(a, 2)
            dicKey = dicKey & "|" & a(i, m)
        Next m
        dicKey = Right(dicKey, Len(dicKey) - 1)
        If Not dicResult.exists(dicKey) Then
         
          For j = 1 To UBound(b, 1)
              n = 0
              iMiss = 0
              For k = 1 To 14
                  If a(i, k) = b(j, k) Then
                      n = n + 1
                  Else
                      ' if more misses than the best so far no point in looking further
                      iMiss = iMiss + 1
                      If iMiss > xMiss Then Exit For
                  End If
              Next k
            
              If n > xmax Then
                  xmax = n
                  xMiss = iPossible - xmax
              End If
              ' if iPossible is reached no point looking further
              ' Shouldn't need this the dictionary lookup so catch it before here
              If xmax = iPossible Then Exit For
          Next j
        Else
            xmax = iPossible
        End If
          c(i, 1) = xmax
    Next i
   
    Range("Q6").Resize(UBound(c, 1), 1) = c
   
    Application.ScreenUpdating = True
   
    Debug.Print Timer - startTime
End Sub

Wow Alex Blakenburg, I am speechless by this update this has reduced time by previous code 00:00:98 Minutes nearly 1 Minute. Previous code were finished in 00:01:28 Minutes and this one in 00:00:20 Minutes. 👌

I am so happy I can’t express you and grateful to you for giving me an excellent time saver solution. It is performing like magic.

I have change and marked this as better ever solution.

Good night, have a safe weekend. And Good Luck! to you forever.

My Best regards,
Moti :)
 
Upvote 0

Forum statistics

Threads
1,215,096
Messages
6,123,074
Members
449,093
Latest member
ripvw

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