Home » Cap and Carry Running Totals

Cap and Carry Running Totals

Find the running total for the groups. The running total will be capped at 100 and remainder will be carried forward. Hence, in row 4, 88+34 = 122. Hence, 22 will be carried forward. Hence, running total in row 5 will be 18+22 = 40

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

Solving the challenge of Cap and Carry Running Totals with Power Query

Power Query solution 1 for Cap and Carry Running Totals, proposed by Bo Rydobon 🇹🇭:
let
  Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content], 
  Group = Table.Combine(
    Table.Group(
      Source, 
      "Group", 
      {
        "T", 
        each Table.FromColumns(
          Table.ToColumns(_)
            & {
              List.RemoveFirstN(
                List.Zip(
                  List.Accumulate(
                    [Weight], 
                    {{0, 0}}, 
                    (s, l) =>
                      let
                        P = List.Last(s){0} + l
                      in
                        s & {{Number.Mod(P, 100), if P < 100 then P else 100}}
                  )
                ){1}, 
                1
              )
            }, 
          Table.ColumnNames(_) & {"Running Total"}
        )
      }
    )[T]
  )
in
  Group
Power Query solution 2 for Cap and Carry Running Totals, proposed by Zoran Milokanović:
let
  Source = Excel.CurrentWorkbook(){[Name = "Input"]}[Content], 
  Solution = Table.FromRecords(
    List.Transform(
      List.Accumulate(
        Table.ToRecords(Source), 
        {}, 
        (s, d) =>
          s
            & {
              let
                lg   = List.Last(s)[Group], 
                lrt  = List.Last(s)[Running Total], 
                rlrt = Number.Mod(lrt, 100), 
                lr   = List.Last(s)[Remainder], 
                cg   = d[Group], 
                cw   = d[Weight]
              in
                if s = {} or lg <> cg then
                  [
                    Group         = cg, 
                    Weight        = cw, 
                    Running Total = if cw > 100 then 100 else cw, 
                    Remainder     = if cw > 100 then cw - 100 else 0
                  ]
                else
                  [
                    Group         = cg, 
                    Weight        = cw, 
                    Running Total = if rlrt + lr + cw > 100 then 100 else rlrt + lr + cw, 
                    Remainder     = if rlrt + lr + cw > 100 then rlrt + lr + cw - 100 else 0
                  ]
            }
      ), 
      each Record.RemoveFields(_, "Remainder")
    )
  )
in
  Solution
Power Query solution 3 for Cap and Carry Running Totals, proposed by Aditya Kumar Darak 🇮🇳:
let
  Source = Excel.CurrentWorkbook(){[Name = "data"]}[Content], 
  MyFun = (T as table) as table =>
    let
      Table = Table.Buffer(T), 
      Calc = List.Generate(
        () => [x = 0, w = Table{x}, y = w[Weight], z = List.Min({100, y})], 
        each [x] < Table.RowCount(Table), 
        each [
          x = [x] + 1, 
          w = Table{x}, 
          y = (if [z] = 100 then [y] - 100 else [y]) + w[Weight], 
          z = List.Min({100, y})
        ], 
        each [w] & [Running Total = [z]]
      ), 
      Final = Table.FromRecords(Calc)
    in
      Final, 
  Group = Table.Group(Source, "Group", {"All", MyFun}), 
  Return = Table.Combine(Group[All])
in
  Return
Power Query solution 4 for Cap and Carry Running Totals, proposed by Alejandro Simón 🇵🇦 🇪🇸:
let
  Source = Excel.CurrentWorkbook(){[Name = "Tabla1"]}[Content], 
  Group = Table.Group(
    Source, 
    {"Group"}, 
    {
      {
        "All", 
        (w) =>
          List.Skip(
            List.Generate(
              () => [x = 1, z = 0, y = w[Weight]{0}, a = 0], 
              each [x] <= Table.RowCount(w) + 1, 
              each [
                a = w[Weight]{[x]}, 
                x = [x] + 1, 
                y = 
                  if [y] + [a] < 100 then
                    [y] + [a]
                  else if [y] + [a] > 100 then
                    [y] + [a] - 100
                  else
                    null, 
                z = if [y] + [a] <= 100 then [y] + [a] else 100
              ], 
              each [z]
            )
          )
      }
    }
  )[[All]], 
  RT = Table.ExpandListColumn(Group, "All")[All], 
  Sol = Table.FromColumns(
    Table.ToColumns(Source) & {RT}, 
    Table.ColumnNames(Source) & {"Running Total"}
  )
in
  Sol
Power Query solution 5 for Cap and Carry Running Totals, proposed by Luan Rodrigues:
let
  Fonte = Tabela1, 
  gp = Table.Group(
    Fonte, 
    {"Group"}, 
    {
      {
        "Contagem", 
        each [
          a = Table.AddIndexColumn(_, "Ind", 1, 1), 
          b = Table.AddColumn(a, "Acc", each List.Sum(List.FirstN(a[Weight], [Ind]))), 
          c = Table.AddColumn(b, "Cond", each Number.IntegerDivide([Acc], 100)), 
          d = Table.AddColumn(c, "Cond2", each Number.Mod([Acc], 100))
        ][d]
      }
    }
  ), 
  exp = Table.ExpandTableColumn(gp, "Contagem", {"Weight", "Ind", "Acc", "Cond", "Cond2"}), 
  gp2 = Table.Group(
    exp, 
    {"Group", "Cond"}, 
    {{"Contagem", each Table.AddIndexColumn(_, "Ind2", 0, 1)}}
  ), 
  exp2 = Table.ExpandTableColumn(gp2, "Contagem", {"Weight", "Acc", "Cond2", "Ind2"}), 
  res = Table.AddColumn(
    exp2, 
    "Running Total", 
    each if [Cond] = 0 then [Cond2] else if [Ind2] = 0 then 100 else [Cond2]
  )[[Group], [Weight], [Running Total]]
in
  res
Power Query solution 6 for Cap and Carry Running Totals, proposed by Hussein SATOUR:
let
  Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content], 
  #"Changed Type" = Table.TransformColumnTypes(Source, {{"Weight", Int64.Type}}), 
  #"Grouped Rows" = Table.Group(
    #"Changed Type", 
    {"Group"}, 
    {{"Count", each _, type table [Group = nullable text, Weight = nullable number]}}
  ), 
  #"Added Custom" = Table.AddColumn(
    #"Grouped Rows", 
    "Custom", 
    each 
      let
        a = Table.AddIndexColumn([Count], "Index", 1), 
        b = Table.AddColumn(a, "Cumul", each List.Sum(List.FirstN(a[Weight], [Index]))), 
        c = Table.AddColumn(b, "IntDiv", each Number.IntegerDivide([Cumul], 100))
      in
        Table.AddColumn(
          c, 
          "Running Total", 
          each 
            if [IntDiv] = 0 then
              [Cumul]
            else if [Index] = 1 then
              List.Min({[Cumul], 100})
            else if [IntDiv] > c[IntDiv]{[Index] - 2} then
              100
            else
              [Cumul] - 100 * [IntDiv]
        )
  ), 
  #"Expanded Custom" = Table.ExpandTableColumn(
    #"Added Custom", 
    "Custom", 
    {"Group", "Weight", "Running Total"}, 
    {"Group.1", "Weight", "Running Total"}
  ), 
  #"Removed Columns" = Table.RemoveColumns(#"Expanded Custom", {"Group", "Count"})
in
  #"Removed Columns"
Power Query solution 7 for Cap and Carry Running Totals, proposed by Felipe Perez Arevalo:
let
  Sumfx2 = (L) =>
    let
      Source = List.Generate(
        () => [
          i  = L, 
          n  = 1, 
          l  = List.Range(i, 0, n), 
          c  = List.Sum(l), 
          j1 = 0 = Number.IntegerDivide(c, 100), 
          j  = Number.IntegerDivide(c, 100), 
          c1 = if j1 then c - 100 * j else 100
        ], 
        each [n] <= List.Count([i]), 
        each [
          i  = L, 
          n  = [n] + 1, 
          l  = List.Range(i, 0, n), 
          c  = List.Sum(l), 
          j1 = [j] = Number.IntegerDivide(c, 100), 
          j  = Number.IntegerDivide(c, 100), 
          c1 = if j1 then c - 100 * j else 100
        ], 
        each [c1]
      )
    in
      Source, 
  Source = Table, 
  GroupBy = Table.Group(
    Source, 
    {"Group"}, 
    {
      {
        "Detail", 
        each Table.AddIndexColumn(_, "Index", 0, 1, Int64.Type), 
        type nullable table [
          Group = nullable text, 
          Weight = nullable Int64.Type, 
          Index = nullable Int64.Type
        ]
      }
    }
  ), 
  AddCustom = Table.AddColumn(GroupBy, "Custom", each [Detail][Weight]), 
  ExpandeDetail = Table.ExpandTableColumn(
    AddCustom, 
    "Detail", 
    {"Weight", "Index"}, 
    {"Weight", "Index"}
  ), 
  AddCustom1 = Table.RemoveColumns(
    Table.AddColumn(ExpandeDetail, "Running Total", each Sumfx2([Custom]){[Index]}, Int64.Type), 
    {"Index", "Custom"}
  )
in
  AddCustom1

Solving the challenge of Cap and Carry Running Totals with Excel

Excel solution 1 for Cap and Carry Running Totals, proposed by Bo Rydobon 🇹🇭:
=LET(a,A2:A18,w,B2:B18,h,100,r,ROW(a),s,MMULT((a=TOROW(a))*(r>=TOROW(r)),w),c,INT(s/h),
HSTACK(a,w,DROP(IF(c-VSTACK(0,c)*(a=VSTACK(0,a)),h,MOD(s,h)),-1)))
Excel solution 2 for Cap and Carry Running Totals, proposed by محمد حلمي:
=HSTACK(A1:B18,REDUCE("Running Total",UNIQUE(A2:A18),LAMBDA(c,n,LET(v,SCAN(0,FILTER(B2:B18,A2:A18=n),LAMBDA(a,d,MOD(a,100)+d)),VSTACK(c,IF(v>100,100,v))))))
Excel solution 3 for Cap and Carry Running Totals, proposed by Kris Jaganah:
=LET(a,A2:A18,b,B2:B18,HSTACK(VSTACK("Group",a),VSTACK("Weight",b),REDUCE("Running Total",UNIQUE(a),LAMBDA(x,y,LET(p,FILTER(b,a=y),q,SCAN(0,p,LAMBDA(v,w,w+MOD(v,100))),VSTACK(x,IF(q>100,100,q)))))))
Excel solution 4 for Cap and Carry Running Totals, proposed by Oscar Mendez Roca Farell:
=HSTACK(A1:B18, REDUCE("Running Total", UNIQUE(A2:A18), LAMBDA(j, y, VSTACK(j, LET(_m, FILTER(B2:B18, A2:A18=y), _s, SCAN(0,_m, LAMBDA(i, x , i+x)), IF( DROP( FREQUENCY( SEQUENCE( INT(MAX(_s)/100)), INT(_s/100)), -1), 100, MOD(_s, 100)))))))
Excel solution 5 for Cap and Carry Running Totals, proposed by Sunny Baggu:
=LET(_input,A2:B18,_group,TAKE(_input,,1),_ug,UNIQUE(_group),
DROP(REDUCE("",_ug,LAMBDA(a,v,VSTACK(a,
LET(_cols2,FILTER(_input,_group=v),_wt,DROP(_cols2,,1),_runtot,SCAN(0,_wt,LAMBDA(a,v,a+v)),_trun,TRUNC(_runtot/100),
_cond1,IFERROR(VSTACK(0,DROP(SCAN(0,SEQUENCE(ROWS(_trun)),LAMBDA(a,v,IF(INDEX(_trun,v,1)<>INDEX(_trun,v+1,1),INDEX(_trun,v+1,1),0))),-1)),0),
_cond2,IFERROR(IF(_cond1,100,0),0),_hundred,_trun*100,_diff,_runtot-_hundred,_fruntot,IF(_wt>=100,100,IFERROR(IF(_cond2,_cond2,_diff),MIN(100,_wt))),
HSTACK(_cols2,_fruntot))))),1))
Excel solution 6 for Cap and Carry Running Totals, proposed by Mohamed Helmy:
=DROP(
REDUCE(0,UNIQUE(A2:A18),LAMBDA(c,n, LET(r,FILTER(B2:B18,A2:A18=n),
v,SCAN(0,r,LAMBDA(a,d,MOD(a,100)+d)),
VSTACK(c,IF(v>100,100,v))))),1)
Excel solution 7 for Cap and Carry Running Totals, proposed by Stevenson Yu:
=HSTACK(A2:B2, LET(A, SUMIFS(B$2:B2,A$2:A2,A2),
MIN(100,A-(INT((A-B2)/100)*100))))

Solving the challenge of Cap and Carry Running Totals with Python in Excel

Python in Excel solution 1 for Cap and Carry Running Totals, proposed by Alejandro Campos:
df = xl("A1:B18", headers=True)
results, carry_over, current_group = [], 0, None
for index, row in df.iterrows():
 group, weight = row['Group'], row['Weight']
 if group != current_group:
 cumulative_sum = 0
 current_group = group
 weight += carry_over
 carry_over = max(0, cumulative_sum + weight - 100)
 cumulative_sum = min(100, cumulative_sum + weight)
 results.append((group, row['Weight'], cumulative_sum))
 if carry_over > 0:
 cumulative_sum = carry_over
 carry_over = 0
result_df = pd.DataFrame(results, columns=['Group', 'Weight', 'Running Total'])
result_df
                    
                  

Solving the challenge of Cap and Carry Running Totals with Excel VBA

Excel VBA solution 1 for Cap and Carry Running Totals, proposed by Vasin Nilyok:
Sub PQ71()
LastRow = Cells(Rows.Count, 1).End(xlUp).Row
For r = 2 To LastRow
 If r = 2 Then
 km = Cells(r, 2)
 Cells(r, 8) = km
 ElseIf Cells(r, 1) = Cells(r - 1, 1) Then
 kmAdded = Cells(r, 2)
 If km + kmAdded > 100 Then
 cumu = kmAdded - toH
 Cells(r, 8) = 100
 km = cumu
 Else
 km = km + kmAdded
 Cells(r, 8) = km
 End If
 ElseIf Cells(r, 1) <> Cells(r - 1, 1) Then
 If Cells(r, 2) > 100 Then
 Cells(r, 8) = 100
 cumu = Cells(r, 2) - 100
 km = cumu
 Else
 km = kmAdded
 Cells(r, 8) = km
 End If
 End If
Next r
End Sub
                    
                  

&&&

Leave a Reply