Home » Generate Sales Figures Per Category

Generate Sales Figures Per Category

A row appears for an alphabet if seq is continuous. When continuity breaks, a new row appears. Missing column documents what numbers were missed between current and last row populated.

📌 Challenge Details and Links
ExcelBI Power Query Challenge Number: 42
Challenge Difficulty: ⭐️⭐️⭐️⭐️⭐️
📥Download Sample File
📥Link to the solutions on LinkedIn

Solving the challenge of Generate Sales Figures Per Category with Power Query

Power Query solution 1 for Generate Sales Figures Per Category, proposed by Bo Rydobon 🇹🇭:
let
  Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content], 
  Offset = Table.FromColumns(
    Table.ToColumns(Source)
      & {{99} & List.Transform(List.RemoveLastN(Source[Seq]), each _ + 1)}
      & {{""} & List.RemoveLastN(Source[Alphabets])}, 
    {"A", "X", "Y", "B"}
  ), 
  Check = Table.AddColumn(Offset, "C", each [A] <> [B] or [X] <> [Y]), 
  Grouped = Table.FromRows(
    Table.Group(
      Check, 
      "C", 
      {
        "T", 
        each {
          [A]{0}, 
          [X]{0}, 
          List.Last([X]), 
          if [X]{0} > [Y]{0} then
            Text.Combine(List.Transform({[Y]{0} .. [X]{0} - 1}, Text.From), ",")
          else
            null
        }
      }, 
      0, 
      (b, e) => Number.From(e)
    )[T], 
    {"Alphabet", "From", "To", "Missing"}
  )
in
  Grouped
Power Query solution 2 for Generate Sales Figures Per Category, proposed by Alejandro Simón 🇵🇦 🇪🇸:
let
  Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content], 
  Grouped1 = Table.Group(
    Source, 
    {"Alphabets"}, 
    {
      {
        "Count", 
        each 
          let
            a = _, 
            b = Table.AddIndexColumn(a, "Idx"), 
            c = Table.AddColumn(b, "next", each try b[Seq]{[Idx] - 1} + 1 otherwise 0), 
            d = Table.FillDown(
              Table.AddColumn(c, "From", each if [Seq] - [next] > 0 then [Seq] else null), 
              {"From"}
            )
          in
            d
      }
    }
  )[[Count]], 
  Combine = Table.Combine(Grouped1[Count]), 
  Grouped2 = Table.Group(Combine, {"Alphabets", "From"}, {{"To", each List.Last([Seq])}}), 
  Index = Table.AddIndexColumn(Grouped2, "Index", 0, 1, Int64.Type), 
  Missing = Table.AddColumn(
    Index, 
    "Missing", 
    each try
      
        if Index[Alphabets]{[Index] - 1} = Index[Alphabets]{[Index]} then
          {Index[To]{[Index] - 1} + 1 .. [From] - 1}
        else
          null
    otherwise
      null
  ), 
  MissingCom = Table.TransformColumns(
    Missing, 
    {"Missing", each try Text.Combine(List.Transform(_, Text.From), ",") otherwise "", type text}
  ), 
  Solucion = Table.RemoveColumns(MissingCom, {"Index"})
in
  Solucion
Power Query solution 3 for Generate Sales Figures Per Category, proposed by Bhavya Gupta:
let
  Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content], 
  Fn = (S, T) =>
    let
      C_1 = List.Generate(
        () => [x = 1, y = 0, Missing = {}], 
        each [y] < List.Count(S), 
        each [
          y       = [y] + 1, 
          x       = if y = 0 then [x] else if S{y} - S{[y]} = 1 then [x] else [x] + 1, 
          Missing = {S{[y]} + 1 .. S{y} - 1}
        ], 
        each [[x], [Missing]]
      ), 
      C_2 = Table.FromColumns(Table.ToColumns(T) & {C_1}, Table.ColumnNames(T) & {"Helper"}), 
      C_3 = Table.ExpandRecordColumn(C_2, "Helper", {"x", "Missing"}, {"x", "Missing"}), 
      C_4 = Table.Group(
        C_3, 
        {"x"}, 
        {
          {"Alphabets", each List.Distinct([Alphabets]){0}}, 
          {"From", each List.Min([Seq])}, 
          {"To", each List.Max([Seq])}, 
          {
            "Missing", 
            each Text.Combine(
              List.Transform(
                List.Combine(List.Select([Missing], each not List.IsEmpty(_))), 
                Text.From
              ), 
              ","
            )
          }
        }
      ), 
      C_5 = Table.RemoveColumns(C_4, {"x"})
    in
      C_5, 
  GroupedWithFn = Table.Combine(
    Table.Group(Source, {"Alphabets"}, {{"All", each Fn([Seq], _)}})[All]
  ), 
  ExpectedOutput = Table.ReplaceValue(GroupedWithFn, "", null, Replacer.ReplaceValue, {"Missing"})
in
  ExpectedOutput
Power Query solution 4 for Generate Sales Figures Per Category, proposed by Eric Laforce:
let
  Source = Excel.CurrentWorkbook(){[Name = "tData42"]}[Content], 
  Group = Table.Group(
    Source, 
    {"Alphabets"}, 
    {
      "Data", 
      each 
        let
          _Seq = List.Buffer(_[Seq]), 
          _Transform = List.Accumulate(
            _[Seq], 
            [R = {}, From = _Seq{0}], 
            (s, c) =>
              let
                _From = if (List.Contains(_Seq, c - 1)) then s[From] else c, 
                _NewR = 
                  if (List.Contains(_Seq, c + 1)) then
                    s[R]
                  else
                    let
                      _PrevTo = if (List.Count(s[R]) > 0) then List.Last(s[R])[To] + 1 else c, 
                      _Missed = Text.Combine(
                        List.Transform({_PrevTo .. (_From - 1)}, Text.From), 
                        ","
                      )
                    in
                      s[R] & {[From = _From, To = c, Missed = _Missed]}
              in
                [From = _From, R = _NewR]
          )
        in
          Table.FromRecords(_Transform[R])
    }
  ), 
  Expand = Table.ExpandTableColumn(Group, "Data", Table.ColumnNames(Group[Data]{0}))
in
  Expand
Power Query solution 5 for Generate Sales Figures Per Category, proposed by Matthias Friedmann:
let
 Source = Excel.CurrentWorkbook(){[Name = "Seq"]}[Content], 
 Shift = Table.FromColumns(
 Table.ToColumns(Source) & {{"-"} & List.RemoveLastN(Source[Alphabets], 1)} & {{0} & List.RemoveLastN(Source[Seq], 1)}, 
 Table.ColumnNames(Source) & {"Shifted Alpha"} & {"Shifted Seq"}
 ), 
 From = Table.AddColumn(
 Shift, 
 "From", 
 each 
 if [Seq] - [Shifted Seq] <> 1
 or [Alphabets] <> [Shifted Alpha]
 then [Seq]
 else null
 ), 
 #"Filled Down" = Table.FillDown(From, {"From"}), 
 #"Grouped Rows" = Table.Group(
 #"Filled Down", 
 {"Alphabets", "From"}, 
 {
 {"To", each List.Max([Seq]), type number}, 
 {"Missing", 
 each 
 Text.Combine(
 List.Transform({_{0}[Shifted Seq] + 1 .. _{0}[Seq] - 1}, each Text.From(_)), 
 ","
 )
 }
 }
 )
in
 #"Grouped Rows"
*Imke Feldmann s. link in the comments
                    
                  
          
Power Query solution 6 for Generate Sales Figures Per Category, proposed by Owen Price:
https://gist.github.com/ncalm/395698fae6452db0097117aaeb73408d
                    
                  
Power Query solution 7 for Generate Sales Figures Per Category, proposed by Victor Wang:
let
  Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content], 
  Accumulate = List.Accumulate(
    Table.ToRecords(Source), 
    [last = 0, alpha = "", thelist = {}], 
    (s, c) =>
      if List.IsEmpty(s[thelist]) then
        [last = c[Seq], alpha = c[Alphabets], thelist = {{c}}]
      else if c[Seq] = s[last] + 1 and c[Alphabets] = s[alpha] then
        [
          last    = c[Seq], 
          alpha   = c[Alphabets], 
          thelist = List.RemoveLastN(s[thelist]) & {List.Last(s[thelist]) & {c}}
        ]
      else
        [last = c[Seq], alpha = c[Alphabets], thelist = s[thelist] & {{c}}]
  ), 
  Transform = List.Transform(
    Accumulate[thelist], 
    each 
      let
        t = Table.FromRecords(_)
      in
        [Alphabets = t[Alphabets]{0}, From = List.Min(t[Seq]), To = List.Max(t[Seq])]
  ), 
  ToTable = Table.FromRecords(Transform), 
  Index = Table.AddIndexColumn(ToTable, "Index", 0, 1, Int64.Type), 
  Missing = Table.AddColumn(
    Index, 
    "Missing", 
    each try
      Text.Combine(
        List.Transform(
          List.RemoveLastN(List.Skip({Index[To]{[Index] - 1} .. Index[From]{[Index]}})), 
          Text.From
        ), 
        ", "
      )
    otherwise
      ""
  ), 
  Remove = Table.RemoveColumns(Missing, {"Index"})
in
  Remove

Solving the challenge of Generate Sales Figures Per Category with Excel

Excel solution 1 for Generate Sales Figures Per Category, proposed by Bo Rydobon 🇹🇭:
=LET(z,
    A2:B15,
    SORTBY(REDUCE({"Alphabets",
    "Missing",
    "From",
    "To"},
    SEQUENCE(
        ROWS(
            z
        )
    ),
    LAMBDA(a,
    x,
    LET(n,
    INDEX(
        z,
        x,
        2
    ),
    b,
    INDEX(
        z,
        x,
        1
    ),
    
l,
    INDEX(
        a,
        ROWS(
            a
        ),
        4
    ),
    d,
    n-1-N(
        l
    ),
    IF((l=n-1)*IF(
        n>1,
        b=INDEX(
            z,
            x-1,
            1
        )
    ),
    VSTACK(
        DROP(
            a,
            -1
        ),
        HSTACK(
            TAKE(
                a,
                -1,
                3
            ),
            n
        )
    ),
    
VSTACK(
    a,
    HSTACK(
        b,
        IF(
            d>0,
            TEXTJOIN(
                ",",
                ,
                SEQUENCE(
                    d,
                    ,
                    l+1
                )
            ),
            ""
        ),
        n,
        n
    )
))))),
    {1,
    4,
    2,
    3}))
Excel solution 2 for Generate Sales Figures Per Category, proposed by Bo Rydobon 🇹🇭:
=SORTBY(REDUCE({"Alphabets",
    "Missing",
    "From",
    "To"},
    B2:B15,
    LAMBDA(a,
    n,
    LET(l,
    INDEX(
        a,
        ROWS(
            a
        ),
        4
    ),
    d,
    n-1-N(
        l
    ),
    
IF((l=n-1)*(OFFSET(
    n,
    -1,
    -1
)=OFFSET(
    n,
    ,
    -1
)),
    VSTACK(
        DROP(
            a,
            -1
        ),
        HSTACK(
            TAKE(
                a,
                -1,
                3
            ),
            n
        )
    ),
    
VSTACK(
    a,
    HSTACK(
        OFFSET(
    n,
    ,
    -1
),
        IF(
            d>0,
            TEXTJOIN(
                ",",
                ,
                SEQUENCE(
                    d,
                    ,
                    l+1
                )
            ),
            ""
        ),
        n,
        n
    )
))))),
    {1,
    4,
    2,
    3})
Excel solution 3 for Generate Sales Figures Per Category, proposed by محمد حلمي:
=LET(
q,
    SCAN(
        ,
        B2:B15=N(
            +B1:B14
        )+1,
        LAMBDA(
            a,
            d,
            IF(
                d,
                a,
                a+1
            )
        )
    ),
    
REDUCE({"Alphabets",
    "To",
    "From",
    "Missing"},
    UNIQUE(
        q
    ),
    
LAMBDA(a,
    d,
    LET(
e,
    FILTER(
        A2:B15,
        q=d
    ),
    
w,
    TAKE(
        e,
        1,
        1
    ),
    
c,
    MIN(
        e
    ),
    
i,
    TAKE(
        a,
        -1
    ),
    
v,
    MAX(
        i
    ),
    
VSTACK(a,
    HSTACK(w,
    c,
    MAX(
        e
    ),
    
ARRAYTOTEXT(IF((w=TAKE(
    a,
    -1,
    1
))*(c<>MIN(
        i
    )),
    
SEQUENCE(
    c-v-1,
    ,
    v+1
),
    ""))))))))
Excel solution 4 for Generate Sales Figures Per Category, proposed by محمد حلمي:
=LET(
M,
    MAP(A1:A14,
    A2:A15,
    B1:B14,
    B2:B15,
    LAMBDA(a,
    b,
    c,
    d,
    
IF((b=a)*(d-1<>c),
    
TEXTJOIN(
    ",",
    ,
    SEQUENCE(
        d-c-1,
        ,
        c+1
    )
),
    ""))),
    
h,
    VSTACK(0,
    SCAN(0,
    B3:B15=(B2:B14+1)*(A3:A15=A2:A14),
    
LAMBDA(
    A,
    D,
    IF(
        D,
        A,
        A+1
    )
))),
    
REDUCE(
    {"Alphabets",
    "From",
    "To",
    "Missing"},
    UNIQUE(
        h
    ),
    LAMBDA(
        a,
        d,
        LET(
            
            e,
            FILTER(
                HSTACK(
                    A2:B15,
                    M
                ),
                h=d
            ),
            
            VSTACK(
                a,
                TAKE(
                    HSTACK(
                        TAKE(
                            e,
                            ,
                            1
                        ),
                        MIN(
                            e
                        ),
                        MAX(
                            e
                        ),
                        TAKE(
                            e,
                            ,
                            -1
                        )
                    ),
                    1
                )
            )
        )
    )
))
Excel solution 5 for Generate Sales Figures Per Category, proposed by Aditya Kumar Darak 🇮🇳:
=LET(
 _d,
     A2:B15,
    
 _al,
     TAKE(
         _d,
          ,
          1
     ),
    
 _sq,
     TAKE(
         _d,
          ,
          -1
     ),
    
 _c1,
     DROP(
         _sq,
          -1
     ) + 1 <> DROP(
         _sq,
          1
     ),
    
 _c2,
     DROP(
         _al,
          -1
     ) <> DROP(
         _al,
          1
     ),
    
 _e1,
     LAMBDA(a,
     b,
     a + (b > 0)),
    
 _c3,
     VSTACK(
         1,
          SCAN(
              1,
               _c1 + _c2,
               _e1
          )
     ),
    
 _c4,
     UNIQUE(
         _c3
     ),
    
 _fn,
     XLOOKUP(
         _c4,
          _c3,
          _al
     ),
    
 _ftf,
     XLOOKUP(
         _c4,
          _c3,
          _sq,
          ,
          ,
          {1,
          -1}
     ),
    
 _c5,
     DROP(
         _ftf,
          1,
          -1
     ) - DROP(
         _ftf,
          -1,
          1
     ) - 1,
    
 _e2,
     LAMBDA(
         a,
          b,
         
          ARRAYTOTEXT(
              IFERROR(
                  SEQUENCE(
                      a,
                       ,
                       b + 1
                  ),
                   ""
              )
          )
          
     ),
    
 _c6,
     VSTACK(
         "",
          MAP(
              _c5,
               DROP(
         _ftf,
          -1,
          1
     ),
               _e2
          )
     ),
    
 _r,
     HSTACK(
         _fn,
          _ftf,
          _c6
     ),
    
 _r
)

Solving the challenge of Generate Sales Figures Per Category with Python

Python solution 1 for Generate Sales Figures Per Category, proposed by Igor Perković:
Masking(ball) 😀 
https://gist.github.com/igorp74/ed901f091043834aafe0aac672f3a4e3

Solving the challenge of Generate Sales Figures Per Category with SQL

SQL solution 1 for Generate Sales Figures Per Category, proposed by Zoran Milokanović:
1/2
WITH -- ORACLE 11G
DATA_PREP
AS
(
 SELECT
 MIN(F.ORDERING) OVER (PARTITION BY F.ALPHABETS) AS ALPHABETS_ORDER
 ,F.ALPHABETS
 ,F.SEQ
 FROM
 (
 SELECT
 T.ALPHABETS
 ,T.SEQ
 ,ROW_NUMBER() OVER (ORDER BY T.TEMP) AS ORDERING
 FROM
 (
 SELECT
 1 AS TEMP
 ,D.ALPHABETS
 ,D.SEQ
 FROM DATA D
 ) T
 ) F
),
EXTENSION (ALPHABETS_ORDER, ALPHABETS, SEQ_START, SEQ_END)
AS
(
 SELECT
 DP.ALPHABETS_ORDER
 ,DP.ALPHABETS
 ,MIN(DP.SEQ) AS SEQ_START
 ,MAX(DP.SEQ) AS SEQ_END
 FROM DATA_PREP DP
 GROUP BY
 DP.ALPHABETS_ORDER
 ,DP.ALPHABETS
 UNION ALL
 SELECT
 E.ALPHABETS_ORDER
 ,E.ALPHABETS
 ,E.SEQ_START + 1 AS SEQ_START
 ,E.SEQ_END
 FROM EXTENSION E
 WHERE
 E.SEQ_START < E.SEQ_END
),
INTERMEDIATE
AS
(
 SELECT
 I2.ALPHABETS_ORDER
 ,I2.ALPHABETS
 ,I2.SEQ
 ,I2.DATA_FLAG
 (PARTITION BY I2.ALPHABETS, I2.DATA_FLAG ORDER BY I2.SEQ ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) A&S SEQ_ID
 FROM
 (
                    
                  

&&

Leave a Reply