简体   繁体   中英

How to count consecutive values in Excel?

At this moment I have this formula that counts consecutive values:

=IF(AB5=0;0;IF(OR(AND(AB4>=100;AB5>=100);AND(AB4<=-100;AB5<=-100));AC4+1;1))

Basically it does this:

0           0
0           0
-110        1
-110        2
-110        3
-100        4
0           0
0           0
0           0
130         1
150         2
0           0
0           0
-100        1
0           0
0           0
0           0
0           0
-110        1
0           0
0           0
0           0
-220        1
-150        2
0           0
0           0

But I want it to do this:

0           0
0           0
-110        0
-110        0
-110        0
-100        4
0           0
0           0
0           0
130         0
150         2
0           0
0           0
-100        1
0           0
0           0
0           0
0           0
-110        1
0           0
0           0
0           0
-220        0
-150        2
0           0
0           0

Or this:

0           0
0           0
-110        4
-110        0
-110        0
-100        0
0           0
0           0
0           0
130         2
150         0
0           0
0           0
-100        1
0           0
0           0
0           0
0           0
-110        1
0           0
0           0
0           0
-220        2
-150        0
0           0
0           0

What is the formula to make this possible ?

I prefer not to have to add more columns since the file is already big...

Using only a formula to do this would be the best thing to do.

Thanks.

You could try a match formula like this:

=IF(AND(ABS(AB5)>=100,AB4=0),MATCH(0,AB6:AB$1048576,0),0)

EDIT

Clearly this is slow for 1,000,000 cells. The inexact match is faster:

=IF(AND(AB5>=100,AB4=0),MATCH(0,AB6:AB$1048576,-1),IF(AND(AB5<=-100,AB4=0),MATCH(-100,AB5:AB$1048576,1),0))

在此输入图像描述

Discussion

Why is Match so slow when on the face of it, it should be only searching a few cells ahead for a match? I am wondering if it is because Match copies the whole range to be searched to a temporary array? Generally this might be a good strategy, but in the particular case when the matching value is near the beginning of the range and the range is very large, it is a bad one.

One more possible approach would be to determine the longest sequence using Frequency (this is fast), then limit the range to be searched using Index, something like:

=MAX(FREQUENCY(IF(ABS(A:A)>=100,ROW(A:A)),IF(A:A=0,ROW(A:A))))

in B1 then

...MATCH(0,AB6:INDEX(A:A,ROW()+B$1),0)

Consecutive counting Version 1

I don't know how to solve your problem with excel, it could be probably done with some array formula which would drastically slow down your even now slow workbook. Therefore I have written a VBA version.
Before you use it you should carefully change the values of the first three variables to fit your needs.
Put the following code into a module :

Option Explicit
'-- Customize BEGIN --------------------

  'Read data from this column, and write to the next, e.g.
  'The AB column is column 28: Read from 28 and write to 29
  Public Const ciCol As Integer = 6

  'The first row of data
  Public Const cLoFirstRow As Long = 5

  'cLoRow is an approximate value e.g. you have 200 rows of data and you
  'estimate that you won't have more than a 1000 in a year, than 1000 is enough,
  'if you have a million then put in a million. The smaller this number the
  'faster the code.
  Public Const cLoRow As Long = 1000
'-- Customize END ----------------------

Sub ConsecutiveCounting1()
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'-- Customize BEGIN --------------------
  'The Abs function eliminates the need for a negative value variable.
  Const cLoLimit As Long = 100
'-- Customize END ----------------------
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  Dim oRng As Range
  Dim loLastRow As Long
  Dim loTemp As Long
  Dim loF1 As Long 'Row Counter
  loLastRow = Cells(Rows.Count, ciCol).End(xlUp).Row
  Set oRng = Range(Cells(cLoFirstRow, ciCol), Cells(loLastRow, ciCol))
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  loTemp = 0
  For loF1 = 1 To oRng.Rows.Count
    If loF1 <> oRng.Rows.Count Then
      If Abs(oRng(loF1, 1)) >= cLoLimit Then
        loTemp = loTemp + 1
        If Abs(oRng(loF1 + 1, 1)) >= cLoLimit Then
          oRng(loF1, 2) = 0
         Else
          oRng(loF1, 2) = loTemp
          loTemp = 0
        End If
       Else
        oRng(loF1, 2) = 0
      End If
     Else 'Last Value
      If Abs(oRng(loF1, 1)) >= cLoLimit Then
        loTemp = loTemp + 1
        oRng(loF1, 2) = loTemp
       Else
        oRng(loF1, 2) = 0
      End If
    End If
  Next
End Sub

And then put the following code in the sheet's code window :

Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
  Dim ColumnNumber As Long
  Dim RowNumber As Long
    ColumnNumber = Target.Column
    RowNumber = Target.Row
    If ColumnNumber <> ciCol Then Exit Sub
    If RowNumber > cLoRow Then Exit Sub
  ConsecutiveCounting1
End Sub

The code automatically changes the value of the cell in the target column without any formula in the resulting cells what should make it very fast. If this isn't the case, an array version could be written, which would make the code dozens of times faster.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM