Count number of occurence of value with condition

ibmy

Board Regular
Joined
Mar 4, 2020
Messages
134
Office Version
  1. 2016
Platform
  1. Windows
Hi,

Sample of data:

1.11.xlsb
BCDEF
1ABAExpected Result
21.31.21.34
31.311.911.92
41.21.2
511.91.3
61.21.2
711.911.9
811.91.3
91.365.7
1011.911.9
1111.91.3
1211.97.8
131.211.9
141.211.9
151.211
1665.77.8
1765.71.3
188.911.9
196.61.3
20881.2
2141.3
Sheet3

Before counting number of occurence value in Column E, these 2 steps must follow :

Step 1) Locate value Column E in Column B, it must exist last (if from top to down) or exist first (from down to top)
Example: E1 value is "1.3", it occur in B2, B3, B9.
B9 is choose because it exist last in column B (from top to down) or exist first in column B (from down to top)

Step 2) Then, count number of occurence the value in Column C, starting from row of it occur in column B (Step 1)
Example: Value "1.3" happen last in B9 so count the number of occurence in Column C starting form C9 to last row in Column C

Properties of Real Data:
1. Row data in Column B and C ranges 100k-450k , for now "countif" works fine but my problem how to do Step 1.
2. Number mostly are in decimal point (3-5 decimal points), Column B, C, E

p/s: sorry for bad English
 

Excel Facts

Do you hate GETPIVOTDATA?
Prevent GETPIVOTDATA. Select inside a PivotTable. In the Analyze tab of the ribbon, open the dropown next to Options and turn it off
This will match the E2 value and find the last occurrence in column B, and then count all occurrences in column C after the last match from column B

Excel Formula:
=COUNTIF(INDIRECT("C" & LOOKUP(2,1/(B2:B500000=E2),ROW(B2:B500000)) & ":C500000"), E2)
 
Upvote 1
Thanks @pitchoute for the reply.

Thanks @AlphaFrog , the formula produce the result I was expected.
I just add "$" at
Excel Formula:
B$2:B$50000=E2
and
Excel Formula:
B$2:B$50000

Is there any way that the time to produce the result can be shorten. Currently :
For 100k row Column B,C and 100 row Column E, it take about 1 minute.
For 450k row Column B,C and 1000 row Column E, it take about 5 minute.

I was thinking, if firstly, finding the last row of value (Column F) then apply "COUNTIF" (Column G), does the time can be shorten?
So there will be 2 formula in Column F and Column G, like this :

1.11.xlsb
BCDEFG
1ABALast RowExpected Result
21.31.21.394
31.311.911.9122
41.21.2
511.91.3
61.21.2
711.911.9
811.91.3
91.365.7
1011.911.9
1111.91.3
1211.97.8
131.211.9
141.211.9
151.211
1665.77.8
1765.71.3
188.92
196.61.3
20881.2
2141.3
Sheet4
 
Upvote 0
Your previous posts indicate you might be open to a VBA option. If so give this a try.
Note:
• This will count values that never appear in Column B but have values in Column C. Let me know if you want to handle those differently.
• It assumes no duplicates in column E

VBA Code:
Sub CountFromPrevColLast()

    Dim sht As Worksheet
    Dim rngCnt As Range, rngData As Range
    Dim arrCnt As Variant, arrData As Variant
    Dim rowLastCnt As Long, rowLastData As Long
    Dim dictCnt As Object, dictKey As String
    Dim rowCnt    
    Dim i As Long
    
    Set sht = ActiveSheet
    
    With sht
        rowLastCnt = .Range("E" & Rows.Count).End(xlUp).Row
        Set rngCnt = .Range("E2:E" & rowLastCnt)
        arrCnt = rngCnt.Value
        
        rowLastData = .Range("B" & Rows.Count).End(xlUp).Row
        Set rngData = .Range("B1:C" & rowLastData)
        arrData = rngData.Value
        ' Expand array by 2 columns
        ReDim Preserve arrCnt(1 To UBound(arrCnt), 1 To 3)
    End With

    Set dictCnt = CreateObject("Scripting.dictionary")
    
    ' Load details range into Dictionary
    For i = 1 To UBound(arrCnt)
        dictKey = arrCnt(i, 1)
        dictCnt(dictKey) = i
    Next i

    ' Count occurences in C from last occurence in column B
    For i = UBound(arrData) To 1 Step -1
        ' Check if value in list and have not yet registered last occurence in column B
        dictKey = arrData(i, 2)
        If dictCnt.exists(dictKey) Then
            rowCnt = dictCnt(dictKey)
            If arrCnt(rowCnt, 3) = "" Then
                arrCnt(rowCnt, 2) = arrCnt(rowCnt, 2) + 1
            End If
        End If
        
        ' If last occurence in column B record row number
        dictKey = arrData(i, 1)
        If dictCnt.exists(dictKey) Then
            rowCnt = dictCnt(dictKey)
            If arrCnt(rowCnt, 3) = "" Then
                arrCnt(rowCnt, 3) = i
            End If
        End If
    Next i
    
    For i = 1 To UBound(arrCnt)
        If arrCnt(i, 2) = "" And arrCnt(i, 3) <> "" Then arrCnt(i, 2) = 0
    Next i

    rngCnt.Offset(, 1).Value = Application.Index(arrCnt, , 2)
End Sub
 
Upvote 1
Solution
Thanks @Alex Blakenburg for the code, Im really appreciate your spending time on helping me.
The code works really fast, it took less than 5 seconds to produce the result.

• This will count values that never appear in Column B but have values in Column C.
I do not get it, sorry since my English not so good but I will try explain about the data.
This is what I understand by above sentence : Let say value "100" not appear in Column B but value "100" could be appear in Column C. If that what it means by above sentence then yes it is.
There are value not appear in Column B but appear in Column C and vice versa.
Also, there are value appear in Column B but not appear in Column C and vice versa. (this will produce result "0" or result "0" could be another reason after last row, the value not exist in Column C)

• It assumes no duplicates in column E
Yes, there no duplicates in column E
Actually, all value column E are distinct value from Column B. I copy all value from Column B to Column E then "remove duplicate". So the number row of Column E always lower than both Column B and Column C. Column B and Column C always have same total row.
From sample, it should be look like this :

1.11.xlsb
BCDEF
1ABAExpected Result
21.31.21.34
31.311.91.22
41.21.211.9
511.91.365.7
61.21.28.9
711.911.96.6
811.91.388
91.365.74
1011.911.9
1111.91.3
1211.97.8
131.211.9
141.211.9
151.211
1665.77.8
1765.71.3
188.92
196.61.3
20881.2
2141.3
mrexcel


Finally, by using same code, change a few lines, then I would like also run for value in Column C in Column K.
Value in Column K are distinct value from Column C same as I did for value in Column B in Column E
Hopefully I can get same code but 2 code (change a few lines) , instead of 1 code that produce all the result because I might change placement of value in different column later on if there is new variable that interest me.

1.11.xlsb
BCDEFGHIJKL
1ABAResultBResult
21.31.21.341.20
31.311.911.9211.9
41.21.21.21.3
511.91.365.765.7
61.21.28.97.8
711.911.96.611
811.91.3882
91.365.74
1011.911.9
1111.91.3
1211.97.8
131.211.9
141.211.9
151.211
1665.77.8
1765.71.3
188.92
196.61.3
20881.2
2141.3
mrexcel 2
Cell Formulas
RangeFormula
F2F2=COUNTIF(INDIRECT("C" & LOOKUP(2,1/(B$2:B$500000=E2),ROW(B$2:B$500000)) & ":C500000"), E2)
L2L2=COUNTIF(INDIRECT("B" & LOOKUP(2,1/(C$2:C$500000=K2),ROW(C$2:C$500000)) & ":B500000"), K2)


This is real data if you would like to take a look : Real Data
 
Upvote 0
I have logged out for the night but so I know for tomorrow, is the logic of column C & B reversed for column K ?
ie Looking for last row in column C and counting matches in Column B that are below that last row ?
 
Upvote 0
@Alex Blakenburg , Exactly, column C & B reversed for column K.

Column E : Look for last row in Column B then count number of occurence in Column C
Column K : Look for last row in Column C then count number of occurence in Column B
 
Upvote 0
Give this a try for column K. Only 4 lines are changed (they all use the word Swapped in the comments)
Ideally we would change it to a called sub and feed it the parameters that change.

VBA Code:
Sub CountFromPrevColLast_SumB()

    Dim sht As Worksheet
    Dim rngCnt As Range, rngData As Range
    Dim arrCnt As Variant, arrData As Variant
    Dim rowLastCnt As Long, rowLastData As Long
    Dim rowCnt
    
    Dim i As Long
    
    Set sht = ActiveSheet
    
    With sht
        rowLastCnt = .Range("K" & Rows.Count).End(xlUp).Row     ' Swapped from column E to Column K - Filter list
        Set rngCnt = .Range("K2:K" & rowLastCnt)                ' Swappedfrom column E to Column K - Filter list
        arrCnt = rngCnt.Value
        
        rowLastData = .Range("B" & Rows.Count).End(xlUp).Row
        Set rngData = .Range("B1:C" & rowLastData)
        arrData = rngData.Value
        ' Expand array by 2 columns
        ReDim Preserve arrCnt(1 To UBound(arrCnt), 1 To 3)
    End With

    Dim dictCnt As Object, dictKey As String

    Set dictCnt = CreateObject("Scripting.dictionary")

    ' Load details range into Dictionary
    For i = 1 To UBound(arrCnt)
        dictKey = arrCnt(i, 1)
        'If Not dictCnt.exists(dictKey) Then
            dictCnt(dictKey) = i
        'End If
    Next i

    ' Count occurences in C from last occurence in column B
    For i = UBound(arrData) To 1 Step -1
        ' Check if value in list and have not yet registered last occurence in column C
        ' Column to count
        dictKey = arrData(i, 1)                                     ' Swapped from 2 to 1 being column C from Column B - column to count
        If dictCnt.exists(dictKey) Then
            rowCnt = dictCnt(dictKey)
            If arrCnt(rowCnt, 3) = "" Then
                arrCnt(rowCnt, 2) = arrCnt(rowCnt, 2) + 1
            End If
        End If
        
        ' If last occurence in column C record row number
        ' Criteria Column
        dictKey = arrData(i, 2)                                     ' Swapped from 1 to 2 being column B from Column C - criteria column
        If dictCnt.exists(dictKey) Then
            rowCnt = dictCnt(dictKey)
            If arrCnt(rowCnt, 3) = "" Then
                arrCnt(rowCnt, 3) = i
            End If
        End If
    Next i
    
    For i = 1 To UBound(arrCnt)
        If arrCnt(i, 2) = "" And arrCnt(i, 3) <> "" Then arrCnt(i, 2) = 0
    Next i

    rngCnt.Offset(, 1).Value = Application.Index(arrCnt, , 2)
End Sub
 
Upvote 1

Forum statistics

Threads
1,223,931
Messages
6,175,465
Members
452,645
Latest member
Tante

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