Forum Discussion
Power Query - Looping calculation
- Anonymous4 years ago
you are absolutely rigth!
let Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WMjIwtFTSUTI0QCJidUDiRiCeJUQIyoRKGAJ5YFlDMGkElzAC8oDIHCQKFzSGCJqCBI3hoiYQURNUK02R1IJEYwE=", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [date = _t, device = _t, plan = _t, res = _t]), q = Table.TransformColumnTypes(Source,{{"date", Int64.Type}, {"device", Int64.Type}, {"plan", Int64.Type}, {"res", Int64.Type}}), calcres=List.Accumulate({0..Table.RowCount(q)-1},{}, (s,c)=> s& {List.Max({0,q[plan]{c} - (List.Sum(List.LastN(s,2))??0)})}) ttc=Table.ToColumns(q), nm=Table.ColumnNames(q), tfc=Table.FromColumns(ttc&{calcres}, nm&{"calcres"}) in tfc - 4 years ago
I resolved my above issue by creating a function, and then invoking the function following a group by step. I have pasted both codes below as reference to the community - but I would still be interested in a solution that hacks the M code - without having to create a function - if possible, to deepen my M knowledge.
Here is the code that works:
The function (named fnListAccumulate) - which is essentially the code provided by @Rocco_sprmnt21 in the accepted solution - with minor changes to convert to a function (red) :
(GrpTbl as table)=>
let
calcres=List.Accumulate({0..Table.RowCount(GrpTbl)-1},{}, (s,c)=> s& {List.Max({0,GrpTbl[plan]{c} - (List.Sum(List.LastN(s,2))??0)})}),
ttc=Table.ToColumns(GrpTbl),
nm=Table.ColumnNames(GrpTbl),
tfc=Table.FromColumns(ttc&{calcres}, nm&{"calcres"})
in
tfcHere is the original table invoking the above function after a group the desired fields (Scenario/Product):
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("jZI7DsMgDIbvwpwBTJyEW1TqGGVq90q9/1AewTJgo0rEYfhC/gfnacC6YBbzfLk4H9/PO72dZeNaEgV2oEIBbNnemBuw/KXLEwiDAYtrTwwhXkIwIZ6YVWLWVjiq5xDTRZDEIT2if6j/WbHsRPtQY0RsJMFAxbW1sr3E5IRQsQ/MvuIemPvOPPzVP6cm/XNs0j/H6KwugY45bImqSaBjdukCdMw2iWDSP0f0/jml98+pqhoU97w4UNzfTGjvCErMURO6fg==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [date = _t, scenario = _t, product = _t, device = _t, plan = _t, res = _t]),
q = Table.TransformColumnTypes(Source,{{"date", Int64.Type}, {"device", Int64.Type}, {"plan", Int64.Type}, {"res", Int64.Type}, {"scenario", type text}, {"product", type text}}),
#"Grouped Rows" = Table.Group(q, {"scenario", "product"}, {{"Allrows", each _, type table [date=nullable number, scenario=nullable text, product=nullable text, device=nullable number, plan=nullable number, res=nullable number]}}),
#"Invoked Custom Function" = Table.AddColumn(#"Grouped Rows", "ListAccumulate", each FnListAccumulate([Allrows])),
#"Removed Other Columns" = Table.SelectColumns(#"Invoked Custom Function",{"ListAccumulate"}),
#"Expanded ListAccumulate" = Table.ExpandTableColumn(#"Removed Other Columns", "ListAccumulate", {"date", "scenario", "product", "device", "plan", "res", "calcres"}, {"date", "scenario", "product", "device", "plan", "res", "calcres"})
in
#"Expanded ListAccumulate"
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WMjIwtFTSUTI0QCJidUDiRiCeJUQIyoRKGAJ5YFlDMGkElzAC8oDIHCQKFzSGCJqCBI3hoiYQURNUK02R1IJEYwE=", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [date = _t, device = _t, plan = _t, res = _t]),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"date", Int64.Type}, {"device", Int64.Type}, {"plan", Int64.Type}, {"res", Int64.Type}}),
ai = Table.AddIndexColumn(#"Changed Type", "Index", 0, 1, Int64.Type),
#"Added Custom" = Table.AddColumn(ai, "rescalc", each List.Max({[plan]-((try ai[res]{[Index]-1} otherwise 0) + (try ai[res]{[Index]-2} otherwise 0)),0}))
in
#"Added Custom"- Stealth024 years ago
Helper I
Thanks.
If I understand it correctly - you have used the DesiredResults column to generate the Rescalc column.
If correct, I may not have been clear in my original message - but the desired column was created manually - just for the purpose of showing what I was looking to achieve - and should not be used to generate the Rescalc column.
Essentially from the table above only the Date, Device and Plan would be part of the intial table - and the calculated column is what I am trying to achieve entirely within PQ. I.e. The current row calculation of the calculated column is dependant on the calculation of the two previous row of that same calculated column.
- Anonymous4 years agoNot applicable
you are absolutely rigth!
let Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WMjIwtFTSUTI0QCJidUDiRiCeJUQIyoRKGAJ5YFlDMGkElzAC8oDIHCQKFzSGCJqCBI3hoiYQURNUK02R1IJEYwE=", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [date = _t, device = _t, plan = _t, res = _t]), q = Table.TransformColumnTypes(Source,{{"date", Int64.Type}, {"device", Int64.Type}, {"plan", Int64.Type}, {"res", Int64.Type}}), calcres=List.Accumulate({0..Table.RowCount(q)-1},{}, (s,c)=> s& {List.Max({0,q[plan]{c} - (List.Sum(List.LastN(s,2))??0)})}) ttc=Table.ToColumns(q), nm=Table.ColumnNames(q), tfc=Table.FromColumns(ttc&{calcres}, nm&{"calcres"}) in tfc- Stealth024 years ago
Helper I
Wow - Thank you. Such an elegant - simple solution - I don't think I would have gotten there on my own - but I understand what was done (so I should be able to replicate for other solutions).
I used the ealier version - which worked perfectly - but noticed you updated the code to make it more dynamic (i.e. on the List.Accumulate and seed). I sincerely appreciate this!
Side note - the updated code is missing a comma between the calcres Step and the ttc Step.