Greg_Deckler's avatar
Greg_Deckler
Community Champion
7 years ago

Cthulhu

Why Cthulhu? Because the mental gymnastics required to figure this out nearly drove me insane. And because the exact reason you would need this measure is probably beyond the comprehension of mere mortals. Besides, what else am I supposed to call it, "Repeating Counter Indexing Thingy"?

 

But, if you need a column or measure that counts a group of things consecutively but restarts after a non-consecutive row, well then you are likely the second person to need this...

Cthulhu = 
VAR __index = CALCULATE(MAX([Index])) //What is my current row index?
VAR __group = CALCULATE(MAX([Animal])) //What is my current group?
VAR __tmpTable1 = FILTER(ALL('Cthulhu'),[Animal]=__group&&[Index]<__index) //Return all rows earlier than the current row within the same "group"
VAR __tmpTable2 = ADDCOLUMNS(__tmpTable1,"__diff",[Index] - MAXX(FILTER(ALL('Cthulhu'),[Index]<EARLIER([Index]) && [Animal]=EARLIER([Animal])),[Index])) //For each returned row, calculate the difference between the current index value and the previous index value within the same group. For rows in grouped sequence, this will be 1 but for rows within a group that are out-of-sequence this value will be greater than 1
VAR __max = MAXX(__tmpTable2,[Index]) //Figure out the max index in the current filtered table.
VAR __maxStart = MAXX(FILTER(__tmpTable2,[__diff]>1),[Index]) //In order to account for "skips" in the grouping, figure out the max index value of the latest "skip" (the row right after the skip where the group starts again) This will be the greatest index where the difference from the previous index in the same group is greater than 1 (previous row)
VAR __tmpTable3 = FILTER(__tmpTable2,[Index]>=__maxStart) //Filter out all the other junk because we don't want to count rows before the skip
RETURN IF(ISBLANK(__max),1,IF(__max=__index-1,COUNTROWS(__tmpTable3)+1,1)) //If __max is blank, we know that we are at the start of the table, so 1. If the max index of our original table is 1 less than the current index, we know that we are in sequence so we count all of our filtered rows (which don't include rows past a "skip"), otherwise return 1 because we know we are on the row immediately after a "skip.

The other person would be this guy Anonymous in this thread: https://community.powerbi.com/t5/Desktop/Consecutive-Row-Counter-Column/td-p/509553/highlight/false

 

 

 

 

 

 

 

15 Replies

  • Greg_Deckler, here's an approach using the newer WINDOW functions.

     

    Local Group Index  = 
    VAR _GlobalGroup_ = /* All rows with current animal up to current row */  
        WINDOW (
            1, ABS, /* From frirst row */
            0, REL, /* Up to current row */
            ORDERBY ( Cthulhu[Index] ),
            PARTITIONBY ( Cthulhu[Animal] )
        )  
    VAR _AddPrevIndex_ = /* Lookup previous index for each row */
        ADDCOLUMNS (
            _GlobalGroup_,
            "@PrevIndex",
    	        VAR _PrevRow_ =
                    OFFSET ( -1, _GlobalGroup_, ORDERBY ( Cthulhu[Index] ) )
    	        VAR _PrevIndex =
                    MAXX ( _PrevRow_, Cthulhu[Index] )
    	        RETURN
                    _PrevIndex
        )
    VAR _Skips_ = /* All rows where prev index isn't current index - 1 */
        FILTER ( _AddPrevIndex_, [@PrevIndex] < Cthulhu[Index] - 1  )
        /* Will be empty if there are no such skips */
    
    VAR _LocalGroupStart = /* Latest skip -- blank if _Skips_ is empty */
        MAXX ( _Skips_, Cthulhu[Index] )
    
    VAR _LocalGroup_ = /* All rows since latest skip */
        FILTER ( _AddPrevIndex_, Cthulhu[Index] >= _LocalGroupStart )
    
    VAR _Rank = /* Current row is the last in the local group */
        COUNTROWS ( _LocalGroup_ )
    
    RETURN  
        _Rank
  • I may be a 3rd guy... Looks like I may be using this work.

    I would have preferred a Power Query based solution, as the mix of PQ and using add column or measure is a bit too unpredictable for a beginner like me. I have lots of PQ in a complex table, along with using this, as an add column.

    It worked! But devs are buffled as to how it is all works. 

     

    Amazing work - I've just signed up to say thank you!... 

  • I think I found a cleaner approach:

    Local Group Index  = 
    VAR _CurrIndex = MAX ( Cthulhu[Index] )
    VAR _CurrGroup = MAX ( Cthulhu[Animal] )
    VAR _LocalGroupStart =
        CALCULATE (
            MAX ( Cthulhu[Index] ),
            ALLSELECTED ( Cthulhu ),
            Cthulhu[Index] < _CurrIndex,
            Cthulhu[Animal] <> _CurrGroup
        )
    VAR _LocalIndex = _CurrIndex - _LocalGroupStart
    RETURN
        _LocalIndex

     

      • AlexisOlson's avatar
        AlexisOlson
        Super User

        I've got a simplification for that problem now too. 🙂

    • MrsBuckley64's avatar
      MrsBuckley64
      New Member

      Hello, I am very new to Power Query, just started watching videos on how to use yesterday... I typed this in and I keep getting a Token Eof expected, I have tried to remove the Local Group Index part and still happens, please help, this is what I need to finish this sheet, thank you!




       

       

      • AlexisOlson's avatar
        AlexisOlson
        Super User

        Power Query uses M, not DAX. It's a completely different language.

  • Anonymous's avatar
    Anonymous
    Not applicable

    Hahaha, I wish the people using this visual truly know the blood sweat and tears behind it! Thanks for your hard work Greg!

    • Anonymous's avatar
      Anonymous
      Not applicable

      Note: this is used to splice up a sensor input by shift hour: ie

       

      shift 1:

      7am hour 1

      8am hour 2

      9am hour 3

       

      Shift 2:

      10pm hour 1

      11pm hour 2

      .....

       

      Not for counting zoo animals!

  • Calimamax2's avatar
    Calimamax2
    Regular Visitor

    I'm so confused.  I'm a not-very-tech-savvy senior so calculations etc throw me for a loop.  I have a data dump from our timekeeping database. Columns include: Employee, Division, Section, PayGrade, Date, Hours, to name a few. There is 11,000 rows with 200 employees and the dates they worked.  I need to add a column to the dataset or a measure to a table visual to show how many consecutive days they worked (including weekend days) so that I can identify those who worked 7 consecutive days or more (and needs to reset after a 1-day gap).  I watched the video and read whatever I could find. And I'm stumped. I tried to copy the Cthulhu calculation and I got an error.  Any help would be appreciated.   (I've attached the calc pic in PBI with the error and the calc in excel so the bottom of the calc shows)

  • jvansickler's avatar
    jvansickler
    Frequent Visitor

    I may be #4 - remains to be seen.  We're taking bi-weekly vuln scan results to populate a metrics dashboard.  Some CVEs (vulns) have recurred on unique hosts due to using an older VM image that contains the vuln, or occasionally spinning up/shutting down a container image that contains the vuln.  We're tracking those as separate instances (x days between first and last scan vuln is present), and having a way to tag each instance will be helpful.  We have 80+ hosts and the accumulated scans are >300k rows and growing.  Power BI Desktop and PowerShell have been instrumental in making use/sense of the data. Powershell is used to extract the scan info from the xml .nessus file, reduce the data to the desired columns and metric info, then compare the previous scan to the current scan and output a file that contains flags for remediated CVEs.  Those files are used by Power BI to slice, dice & display the data.