Home » Custom Grouping! Part 17

Custom Grouping! Part 17

Solving Custom Grouping Part 17 challenge by Power Query, Power BI, Excel, Python and R

Group the rows until encountering a missing date. Each group should contain all rows until the first instance of a missing date

📌 Challenge Details and Links
Challenge Number: 187
Challenge Difficulty: ⭐⭐⭐
📥Download Sample File
📥Link to the solutions on LinkedIn

Solving the challenge of Custom Grouping! Part 17 with Power Query

Power Query solution 1 for Custom Grouping! Part 17, proposed by Zoran Milokanović:
let
  Source = Excel.CurrentWorkbook(){[Name = "Input"]}[Content], 
  G = Table.ToRows(
    Table.Group(
      Source, 
      "Date", 
      {"_", each [Sales]}, 
      0, 
      (b, n) =>
        let
          d = Source[Date], 
          p = each List.PositionOf(d, _)
        in
          Byte.From(
            Number.From(n - b) <> List.Count(List.Distinct(List.Range(d, p(b), p(n) - p(b))))
          )
    )
  ), 
  _ = Table.FromRows(
    List.TransformMany(G, each {List.PositionOf(G, _) + 1}, (i, _) => {_, List.Sum(i{1})}), 
    {"Group", "Total Sales"}
  )
in
  _
Power Query solution 2 for Custom Grouping! Part 17, proposed by Brian Julius:
let
  Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content], 
  ReType = Table.TransformColumnTypes(Source, {"Date", type date}), 
  AddIdx = Table.AddIndexColumn(ReType, "Index"), 
  AddPrev = Table.AddColumn(
    AddIdx, 
    "PrevDate", 
    each if [Index] = 0 then [Date] else ReType[Date]{[Index] - 1}, 
    type date
  ), 
  AddDeviate = Table.FillDown(
    Table.AddColumn(
      AddPrev, 
      "Deviate", 
      each 
        if [Index] = 0 then
          1
        else if Number.From([Date]) - 1 <= Number.From([PrevDate]) then
          null
        else
          [Index]
    ), 
    {"Deviate"}
  ), 
  GroupTotal = Table.Group(
    AddDeviate, 
    {"Deviate"}, 
    {{"Total Sales", each List.Sum([Sales]), type number}}
  ), 
  AddGpNum = Table.SelectColumns(
    Table.AddIndexColumn(GroupTotal, "Group", 1, 1, Int64.Type), 
    {"Group", "Total Sales"}
  )
in
  AddGpNum
Power Query solution 3 for Custom Grouping! Part 17, proposed by Alejandro Simón 🇵🇦 🇪🇸:
let
Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
Idx = Table.AddIndexColumn(Source, "Idx", 0),
Grp = Table.Group(Idx, "Idx", {{"A", each 
 let
 a = _,
 b = List.Sum([Sales])
 in b}},0, 
 (x,y)=> Number.From(Number.From(Idx[Date]{y}-Idx[Date]{y-1})>1)),
Sol = Table.FromColumns({{1..List.Count(Grp[A])},Grp[A]},{"Group", "Total Sales"})
in
Sol 
Power Query solution 4 for Custom Grouping! Part 17, proposed by Krzysztof Kominiak:
let
  Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content], 
  Base = Table.TransformColumns(Source, {"Date", Number.From}), 
  Diff = Table.FromColumns(
    Table.ToColumns(Base)
      & {
        List.Accumulate(
          {0 .. List.Count(Base[Date]) - 1}, 
          {}, 
          (s, c) => s & {try Base[Date]{c} - Base[Date]{c - 1} otherwise 0}
        )
      }, 
    Table.ColumnNames(Source) & {"Diff"}
  ), 
  Sum = Table.Group(
    Diff, 
    "Diff", 
    {{"Total Sales", each List.Sum([Sales])}}, 
    0, 
    (x, y) => Byte.From(y > 1)
  ), 
  Result = Table.AddIndexColumn(Sum, "Group", 1, 1)[[Group], [Total Sales]]
in
  Result
Power Query solution 5 for Custom Grouping! Part 17, proposed by Kris Jaganah:
let
  A = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content], 
  B = Table.ToRows(A), 
  C = List.Generate(
    () => [a = 0, b = B{a}{0}, c = 1, d = B{a}{1}], 
    each [a] < List.Count(B), 
    each [
      a = [a] + 1, 
      b = B{a}{0}, 
      c = if Number.From(b - [b]) > 1 then [c] + 1 else [c], 
      d = B{a}{1}
    ], 
    each {[c], [d]}
  ), 
  D = List.Transform(
    List.Distinct(List.Zip(C){0}), 
    (v) => {v, List.Sum(List.Zip(List.Select(C, each _{0} = v)){1})}
  ), 
  E = Table.FromRows(D, {"Group", "Total Sales"})
in
  E
Power Query solution 6 for Custom Grouping! Part 17, proposed by Abdallah Ally:
let
  Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content], 
  AddCol = Table.AddColumn(
    Source, 
    "Data", 
    each [
      a = Table.PositionOf(Source, _), 
      b = if a = 0 or Date.AddDays(Source[Date]{a - 1}, 1) < Source[Date]{a} then 1 else 0
    ][b]
  ), 
  Group = Table.Group(AddCol, "Data", {"Total Sales", each List.Sum([Sales])}, 0, (x, y) => y), 
  Result = Table.AddIndexColumn(Group, "Group", 1)[[Group], [Total Sales]]
in
  Result
Power Query solution 7 for Custom Grouping! Part 17, proposed by Kris Jaganah:
let
  A = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content], 
  B = Table.TransformColumnTypes(A, {{"Date", Int64.Type}}), 
  C = Table.Group(B, "Date", {"Sum", each List.Sum([Sales])}), 
  D = Table.Group(
    C, 
    "Date", 
    {"Total Sales", each List.Sum([Sum])}, 
    0, 
    (x, y) => Number.From(y - 1 <> List.Last(List.Select(C[Date], (v) => v < y), y + 1))
  ), 
  E = Table.AddIndexColumn(D, "Group", 1)[[Group], [Total Sales]]
in
  E
Power Query solution 8 for Custom Grouping! Part 17, proposed by CA Raghunath Gundi:
let
  Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content], 
  Grp1 = Table.Group(Source, {"Date"}, {{"Sum", each List.Sum([Sales]), type number}}), 
  Ind = Table.AddIndexColumn(Grp1, "Index", 0, 1, Int64.Type), 
  PrevDay = Table.AddColumn(Ind, "PrevDay", each ({null} & Ind[Date]){[Index]}), 
  Gap = Table.FillUp(
    Table.AddColumn(PrevDay, "Gap", each Duration.Days([Date] - [PrevDay]) - 1, Int64.Type), 
    {"Gap"}
  ), 
  Replace = Table.ReplaceValue(Gap, 0, 1, Replacer.ReplaceValue, {"Gap"}), 
  Grp2 = Table.Group(Replace, {"Gap"}, {{"Total Sales", each List.Sum([Sum]), type number}}, 0), 
  #"Added Index" = Table.SelectColumns(
    Table.AddIndexColumn(Grp2, "Group", 1, 1, Int64.Type), 
    {"Group", "Total Sales"}
  )
in
  #"Added Index"
Power Query solution 9 for Custom Grouping! Part 17, proposed by Meganathan Elumalai:
let
  Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content], 
  Result = Table.Group(
    Table.FromColumns(
      {
        [
          Lst = List.Skip(Source[Date]), 
          fin = List.Accumulate(
            List.Positions(Lst), 
            {1}, 
            (s, c) =>
              s
                & {
                  if Duration.Days(Lst{c} - Source[Date]{c}) <= 1 then
                    List.Max(s)
                  else
                    List.Max(s) + 1
                }
          )
        ][fin]
      }
        & {Source[Sales]}, 
      {"Group", "Sales"}
    ), 
    "Group", 
    {{"Total sales", each List.Sum([Sales])}}
  )
in
  Result
Power Query solution 10 for Custom Grouping! Part 17, proposed by Seokho MOON:
let
  Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content], 
  Rows = Table.ToRows(Source), 
  Recs = List.Accumulate(
    List.Skip(Rows), 
    {[Date = Rows{0}{0}, Group = 1, Total Sales = Rows{0}{1}]}, 
    (a, v) =>
      if v{0} > Date.AddDays(List.Last(a)[Date], 1) then
        a & {[Date = v{0}, Group = List.Last(a)[Group] + 1, Total Sales = v{1}]}
      else
        List.RemoveLastN(a)
          & {
            [
              Date        = v{0}, 
              Group       = List.Last(a)[Group], 
              Total Sales = List.Last(a)[Total Sales] + v{1}
            ]
          }
  ), 
  Res = Table.FromRecords(Recs)[[Group], [Total Sales]]
in
  Res
Power Query solution 11 for Custom Grouping! Part 17, proposed by Seokho MOON:
let
  Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content], 
  AddIdx = Table.AddIndexColumn(Source, "Idx", - 1), 
  Group = Table.Group(
    AddIdx, 
    {"Date", "Idx"}, 
    {"Total Sales", each List.Sum([Sales])}, 
    0, 
    (x, y) => Number.From(y[Date] > Date.AddDays(AddIdx[Date]{y[Idx]}, 1))
  ), 
  Res = Table.AddIndexColumn(Group, "Group", 1)[[Group], [Total Sales]]
in
  Res
Power Query solution 12 for Custom Grouping! Part 17, proposed by Alexandre Garcia:
let
H = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
P = List.Generate( ()=> [a = 0, b = H[Date]{0}, c = 1], each [a] < List.Count(H[Date]), each [ a = [a] + 1, b = Number.From(H[Date]{a}) - Number.From(H[Date]{[a]}) > 1, c = if b then [c] + 1 else [c]], each [c]),
L = Table.FromColumns({P} & List.Skip (Table.ToColumns(H)), {"Group","x"}),
C = Table.Group(L, "Group", {"Total Sales", each List.Sum([x])})
in C
Power Query solution 13 for Custom Grouping! Part 17, proposed by Vida Vaitkunaite:
let
  Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content], 
  Custom = Table.FromColumns(
    {Source[Date], Source[Sales], {null} & List.RemoveLastN(Source[Date], 1)}, 
    {"Date", "Sales", "Prev"}
  ), 
  Diff = Table.AddColumn(Custom, "Days", each Duration.Days([Date] - [Prev])), 
  Group = Table.Group(
    Diff, 
    "Days", 
    {{"Total Sales", each List.Sum([Sales])}}, 
    0, 
    (x, y) => Number.From(y > 1)
  ), 
  Final = Table.AddIndexColumn(Group, "Group", 1, 1)[[Group], [Total Sales]]
in
  Final

Solving the challenge of Custom Grouping! Part 17 with Excel

Excel solution 1 for Custom Grouping! Part 17, proposed by 🇰🇷 Taeyong Shin:
=LET(
    d,
    N(
        +B:.B
    ),
    g,
    GROUPBY(
        SCAN(
            0,
            DROP(
                d,
                1
            )-DROP(
                d,
                -1
            )>1,
            SUM
        ),
        N(
            +DROP(
                C:.C,
                1
            )
        ),
        SUM,
        ,
        0
    ),
    IF(
        g,
        g,
        {"Group",
        "TotalSales"}
    )
)
Excel solution 2 for Custom Grouping! Part 17, proposed by Oscar Mendez Roca Farell:
=GROUPBY(
    SCAN(
        0,
        B3:B19-N(
            +B2:B18
        )>1,
        SUM
    ),
    C3:C19,
    SUM,
    ,
    0
)
Excel solution 3 for Custom Grouping! Part 17, proposed by Kris Jaganah:
=GROUPBY(SCAN(,
    N((B3:B19-VSTACK(
        0,
        DROP(
            B3:B19,
            -1
        )
    ))>1),
    SUM),
    C3:C19,
    SUM,
    ,
    0)
Excel solution 4 for Custom Grouping! Part 17, proposed by Imam Hambali:
=LET(    ud,
     UNIQUE(
         B3:B19
     ),    d,
     ud-VSTACK(
         0,
         DROP(
             ud,
             -1
         )
     ),    g,
     SCAN(
         0,
          IF(
              d>1,
              1,
              0
          ),
         SUM
     ),    VSTACK(
        {"Group",
        "Total Sales"},
         GROUPBY(
             XLOOKUP(
                 B3:B19,
                 ud,
                 g
             ),
             C3:C19,
             SUM,
             0,
             0
         )
    ))
Excel solution 5 for Custom Grouping! Part 17, proposed by Ivan William:
=LET(
    d,
    B3:B19,
    GROUPBY(
        XMATCH(
            d,
            UNIQUE(
                TOCOL(
                    d/ISNA(
                        XMATCH(
                            d,
                            d+1
                        )
                    ),
                    2
                )
            ),
            -1
        ),
        C3:C19,
        SUM,
        ,
        0
    )
)
Excel solution 6 for Custom Grouping! Part 17, proposed by Sunny Baggu:
=LET(
 _a,
     SCAN(          1,          N(
              VSTACK(
                  1,
                   B4:B19 - B3:B18
              ) > 1
          ),          LAMBDA(
              a,
               v,
               a + v
          )     ), _g,
     UNIQUE(
         _a
     ), _s,
     MAP(_g,
     LAMBDA(a,
     SUM(C3:C19 * (_a = a)))), HSTACK(
     _g,
      _s
 )
)
Excel solution 7 for Custom Grouping! Part 17, proposed by Bilal Mahmoud kh.:
=LET(a,
    DROP(REDUCE(,
    DAY(
        B3:B19
    ),
    LAMBDA(x,
    y,
    LET(n,
    IF(
        COUNT(
            x
        )>1,
        DROP(
            x,
            -1
        ),
        x
    ),
    m,
    INDEX(
        x,
        COUNT(
            x
        ),
        1
    ),
    i,
    INDEX(
        n,
        COUNT(
            n
        ),
        1
    ),
    IF((y-m)>1,
    VSTACK(
        n,
        i+1,
        y
    ),
    VSTACK(
        n,
        i,
        y
    ))))),
    -1),
    REDUCE(
        {"Group",
        "Total sales"},
        UNIQUE(
            a
        ),
        LAMBDA(
            v,
            w,
            VSTACK(
                v,
                HSTACK(
                    w,
                    SUM(
                        FILTER(
                            C3:C19,
                            a=w
                        )
                    )
                )
            )
        )
    ))
Excel solution 8 for Custom Grouping! Part 17, proposed by ferhat CK:
=LET(b,
    SCAN(1,
    VSTACK(
        B3,
        B3:B18
    )-B3:B19,
    LAMBDA(a,
    v,
    IF((v=0)+(v=-1),
    a,
    a+1))),
    GROUPBY(
        VSTACK(
            "Group",
            b
        ),
        VSTACK(
            "Total Sales",
            C3:C19
        ),
        SUM,
        3,
        0
    ))
Excel solution 9 for Custom Grouping! Part 17, proposed by Hamidi Hamid:
=LET(j,DAY(B3:B19),jd,VSTACK(DROP(j,1),0),w,j-jd,k,IF(w<-1,w,""),g,TOCOL(HSTACK(C3:C19,IF(k="",1/0,"")),3),z,GROUPBY(" "&SCAN(1,g="",SUM),g,SUM,0,0),z)
Excel solution 10 for Custom Grouping! Part 17, proposed by Henk-Jan van Well:
= LET(
 d,
     tData[Date], g,
     VSTACK(0,
    SCAN(0,
    (DROP(
        d,
        1
    )-DROP(
        d,
        -1
    ))>1,
    LAMBDA(
        a,
        b,
        a+b
    ))), u,
     UNIQUE(
         g
     ), HSTACK(
     u,
     MMULT(
         N(
             u=TRANSPOSE(
         g
     )
         ),
         tData[Sales]
     )
 )
 )
Excel solution 11 for Custom Grouping! Part 17, proposed by Hussein SATOUR:
=LET(
    d,
    B3:B19,
    GROUPBY(
        SCAN(
            0,
            d-VSTACK(
                0,
                DROP(
                    d,
                    -1
                )
            )>1,
            SUM
        ),
        C3:C19,
        SUM
    )
)
Excel solution 12 for Custom Grouping! Part 17, proposed by Md. Zohurul Islam:
=LET(
    u,
    B3:B19,
    v,
    C3:C19,    hdr,
    HSTACK(
        "Group",
        "Total Sales"
    ),    a,
    DROP(
        u,
        1
    )-DROP(
        u,
        -1
    ),    b,
    IF(
        a<=1,
        0,
        1
    ),    c,
    SCAN(
        0,
        VSTACK(
            1,
            b
        ),
        SUM
    ),    d,
    GROUPBY(
        c,
        v,
        SUM,
        0,
        0
    ),    e,
    VSTACK(
        hdr,
        d
    ),    e
)
Excel solution 13 for Custom Grouping! Part 17, proposed by Meganathan Elumalai:
=LET(
    dt,
    B3:B19,
    GROUPBY(
        VSTACK(
            "Group",
            REDUCE(
                1,
                DROP(
                    dt,
                    1
                )-DROP(
                    dt,
                    -1
                )<=1,
                LAMBDA(
                    a,
                    v,
                    VSTACK(
                        a,
                        IF(
                            v,
                            MAX(
                                a
                            ),
                            MAX(
                                a
                            )+1
                        )
                    )
                )
            )
        ),
        C2:C19,
        SUM,
        3,
        0
    )
)
Excel solution 14 for Custom Grouping! Part 17, proposed by Nicolas Micot:
=LET(_groups;
    ASSEMB.V(
        1;
        SCAN(
            1;
            B4:B19-B3:B18;
            LAMBDA(
                l_valeurInit;
                l_difDates;
                l_valeurInit+SI(
                    l_difDates>1;
                    1;
                    0
                )
            )
        )
    );_uniqueGroups;
    UNIQUE(
        _groups
    );_totalSalesByGroup;
    MAP(_uniqueGroups;
    LAMBDA(l_group;
    SOMME(C3:C19*(_groups=l_group))));ASSEMB.H(
    _uniqueGroups;
    _totalSalesByGroup
))
Excel solution 15 for Custom Grouping! Part 17, proposed by Pieter de B.:
=GROUPBY(
    SCAN(
        1,
        B3:B19,
        LAMBDA(
            a,
            b,
            IF(
                b>@+TAKE(
                    B3:b,
                    -2
                )+1,
                a+1,
                a
            )
        )
    ),
    C3:C19,
    SUM,
    ,
    0
)

Solving the challenge of Custom Grouping! Part 17 with Python

Python solution 1 for Custom Grouping! Part 17, proposed by Konrad Gryczan, PhD:
import pandas as pd

path = "CH-187 Custom Grouping.xlsx"
input = pd.read_excel(path, usecols="B:C", skiprows=1, nrows=17)
test = pd.read_excel(path, usecols="G:H", skiprows=1, nrows=5).astype('int32')

input['Group'] = (input['Date'].diff().dt.days.fillna(0).astype(int) > 1).cumsum() + 1
result = input.groupby('Group', as_index=False)['Sales'].sum().rename(columns={'Sales': 'Total Sales'}).astype({'Total Sales': 'int32'})

print(result.equals(test)) # True
Python solution 2 for Custom Grouping! Part 17, proposed by Abdallah Ally:
import pandas as pd
from datetime import timedelta

# Load the Excel file
file_path = 'CH-187 Custom Grouping.xlsx'
df = pd.read_excel(io=file_path, usecols='B:C', skiprows=1)

# Perform data transformation
df['Group'] = (
 df['Date'] > df['Date'].shift(1).map(lambda x: x + timedelta(days=1))
).cumsum() + 1

df = (
 df
 .groupby('Group')['Sales'].sum()
 .reset_index()
 .rename(columns={'Sales': 'Total Sales'})
)

# Display the final results
df

Solving the challenge of Custom Grouping! Part 17 with Python in Excel

Python in Excel solution 1 for Custom Grouping! Part 17, proposed by Alejandro Campos:
df = xl("B2:C19", headers=True)
df['Date'] = pd.to_datetime(df["Date"], format="%d/%m/%Y")
df["Group"] = (df["Date"].diff().dt.days > 1).cumsum() + 1
df = df.groupby("Group")["Sales"].sum().reset_index(name="Total Sales")

Solving the challenge of Custom Grouping! Part 17 with R

R solution 1 for Custom Grouping! Part 17, proposed by Konrad Gryczan, PhD:
library(tidyverse)
library(readxl)

path = "files/CH-187 Custom Grouping.xlsx"
input = read_excel(path, range = "B2:C19")
test = read_excel(path, range = "G2:H7")

result = input %>%
 mutate(diff = difftime(lead(Date), Date, units = "days") %>% as.numeric()) %>%
 mutate(Group = cumsum(lag(diff, default = 0) > 1) + 1) %>%
 summarise(`Total Sales` = sum(Sales, na.rm = T), .by = Group)

all.equal(result, test)
#> [1] TRUE

Solving the challenge of Custom Grouping! Part 17 with Google Sheets

Google Sheets solution 1 for Custom Grouping! Part 17, proposed by Peter Krkos:
PowerQuery solution:
https://docs.google.com/spreadsheets/d/1zR5IZLz8OT76vhaPEHfsPrw8-RDKnLyyqS49IJjdhFk/edit?pli=1&gid=2008052562#gid=2008052562

Leave a Reply