Fill in all empty values with average of contiguous non-empty values on immediate left. Hence, for Company A, Mar would be average of Jan and Feb. Jun would be average of Apr and May (Mar was empty, hence contiguous non-empty values are Apr and May on immediate left) For C, Jan would be empty as there is no non-empty on immediate left. For May, it would be average of Feb, Mar and Apr
📌 Challenge Details and Links
ExcelBI Power Query Challenge Number: 120
Challenge Difficulty: ⭐️⭐️⭐️⭐️
📥Download Sample File
📥Link to the solutions on LinkedIn
Solving the challenge of Average Fill for Blank Months with Power Query
Power Query solution 1 for Average Fill for Blank Months, proposed by Bo Rydobon 🇹🇭:
let
Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content],
Ans = Table.FromRows(
List.Transform(
Table.ToRows(Source),
each List.Transform(
List.Positions(_),
(n) =>
if _{n} <> null then
_{n}
else
List.Last(
List.RemoveNulls(
Table.Group(
Table.FromValue(List.FirstN(List.Skip(_), n)),
"Value",
{"A", each Number.Round(List.Average([Value]))},
0,
(b, e) => Number.From(e = null)
)[A]
)
)
)
),
Table.ColumnNames(Source)
)
in
Ans
Power Query solution 2 for Average Fill for Blank Months, proposed by Zoran Milokanović:
let
Source = Excel.CurrentWorkbook(){[Name = "Input"]}[Content],
C = each _ is null,
K = List.Skip,
S = Table.FromRows(
List.Transform(
Table.ToRows(Source),
each
let
r = List.Reverse(K(_)),
s = {_{0}}
& List.Accumulate(
List.Positions(r),
{},
(s, c) => {
if C(r{c}) then
Number.Round(List.Average(List.FirstN(K(K(r, c + 1), C), each not C(_))))
else
r{c}
}
& s
)
in
s
),
Table.ColumnNames(Source)
)
in
S
Power Query solution 3 for Average Fill for Blank Months, proposed by Alejandro Simón 🇵🇦 🇪🇸:
let
Source = Excel.CurrentWorkbook(){0}[Content],
Calc = Table.AddColumn(
Source,
"Custom",
each
let
a = List.Skip(Record.ToList(_)),
b = List.Transform(List.PositionOf(a, null, Occurrence.All), each List.FirstN(a, _)),
c = List.Transform(
{0 .. List.Count(b) - 1},
each Number.Round(List.Average(List.Difference(b{_}, try b{_ - 1} otherwise {null})))
),
d = List.Transform(
{0 .. List.Count(c) - 1},
each try if c{_} = null then c{_ - 1} else c{_} otherwise null
),
e = List.Zip({d, List.PositionOf(a, null, Occurrence.All)}),
f = List.Sort(
List.Select(List.Zip({a, List.Positions(a)}), each _{0} <> null) & e,
each _{1}
),
g = Table.FromRows({List.Transform(f, each _{0})}, List.Skip(Table.ColumnNames(Source)))
in
g
)[[Company], [Custom]],
Sol = Table.ExpandTableColumn(Calc, "Custom", Table.ColumnNames(Calc[Custom]{0}))
in
Sol
Power Query solution 4 for Average Fill for Blank Months, proposed by Alejandro Simón 🇵🇦 🇪🇸:
let
Source = Excel.CurrentWorkbook(){0}[Content],
Calc = Table.AddColumn(
Source,
"A",
each Table.FromRows(
{
let
a = List.Skip(Record.ToList(_)),
b = List.Transform(
{0 .. List.Count(a) - 1},
each
if a{_} is null then
let
c = List.Reverse(List.Transform({0 .. _ - 1}, (x) => a{x})),
d = List.PositionOf(c, null, Occurrence.All),
e =
if List.IsEmpty(d) then
Number.Round(List.Average(c))
else
Number.Round(List.Average(List.Transform({0 .. List.Last(d) - 1}, each c{_})))
in
e
else
a{_}
)
in
b
},
List.Skip(Table.ColumnNames(Source))
)
)[[Company], [A]],
Sol = Table.ExpandTableColumn(Calc, "A", Table.ColumnNames(Calc[A]{0}))
in
Sol
Power Query solution 5 for Average Fill for Blank Months, proposed by Luan Rodrigues:
let
Fonte = Tabela1,
sub = Table.ReplaceValue(Fonte,null,"|",Replacer.ReplaceValue,List.RemoveFirstN(Table.ColumnNames(Fonte))),
tab = Table.AddColumn(sub, "Personalizar", each
[a = Text.Split(Text.Combine(List.Transform(List.RemoveFirstN(Record.FieldValues(_),1),(x)=> Text.From(x)),", "),", |"),
b = List.Combine(List.Transform(a, each {_} & {Number.Round(List.Average(List.Transform(List.Select(Text.Split(Text.Remove(_,"|"),","), each _ <> "" ),Number.From )))})),
c = List.Select(List.Combine(List.Transform(b, each try Text.Split(Text.From(_),", ") otherwise {null})), each _ <> "|" and _ <> ""),
d = Table.TransformColumnTypes(Table.FillDown(Table.FromColumns({List.RemoveLastN(c,1)}),{"Column1"}),{"Column1", type number}),
e = Table.Transpose(if Table.RowCount(d) < List.Count(List.RemoveFirstN(Table.ColumnNames(Fonte))) then hashtag#table({"Column1"},{{null}})&d else d,List.RemoveFirstN(Table.ColumnNames(Fonte)) )
][e])[[Company],[Personalizar]],
res = Table.ExpandTableColumn(tab, "Personalizar", List.RemoveFirstN(Table.ColumnNames(Fonte)))
in
res
Power Query solution 6 for Average Fill for Blank Months, proposed by Eric Laforce:
let
Source = Excel.CurrentWorkbook(){[Name = "tData120"]}[Content],
Transform = List.Transform(
Table.ToRows(Source),
each List.Accumulate(
List.Skip(_),
[r = {_{0}}, nn = {}, prev = null],
(s, c) =>
let
_AvgNN = (c ?? Number.Round(List.Average(s[nn]))) ?? s[prev]
in
if (c is null) then
[r = s[r] & {_AvgNN ?? s[prev]}, nn = {}, prev = _AvgNN]
else
[r = s[r] & {c}, nn = s[nn] & {c}, prev = s[prev]]
)[r]
),
ToTable = Table.FromRows(Transform, Table.ColumnNames(Source))
in
ToTable
Power Query solution 7 for Average Fill for Blank Months, proposed by Szabolcs Phraner:
let
//custom function to be used on rows
InsertAvg = (list) =>
let
List = list,
Pos = List.Positions(List),
Acc = List.Accumulate(
Pos,
{},
(s, c) =>
let
v = List{c},
avg = try
Number.Round(List.Average(List.Range(List, c - 2, c)))
otherwise
if Value.Type(List{c - 1}) = type text then null else List{c - 1}
in
if v = null then s & {avg} else s & {v}
)
in
Acc,
Table = Excel.CurrentWorkbook(){[Name = "Table"]}[Content],
Transform = List.Transform(Table.ToRows(Table), InsertAvg),
TableFromRows = Table.FromRows(Transform, Table.ColumnNames(Table))
in
TableFromRows
Solving the challenge of Average Fill for Blank Months with Excel
Excel solution 1 for Average Fill for Blank Months, proposed by Bo Rydobon 🇹🇭:
=VSTACK(A1:G1,SCAN(0,A2:G6,LAMBDA(a,v,LET(b,TAKE(A2:v,-1),IF(v<>"",v,IFERROR(ROUND(AVERAGE(DROP(b,,XMATCH(0,-ISNUMBER(DROP(b,,-1)),,-1))),),IF(N(a),a,"")))))))
Excel solution 2 for Average Fill for Blank Months, proposed by محمد حلمي:
=LET(b,A1:G6,r,LAMBDA(e,SCAN(0,b,LAMBDA(a,d,IF(N(d),a+d^e)))),SCAN(,IF(b>0,b,DROP(HSTACK(0,ROUND(r(1)/r(0),)),,-1)),LAMBDA(a,d,IFERROR(d,IF(N(a),a,"")))))
Excel solution 3 for Average Fill for Blank Months, proposed by Kris Jaganah:
=HSTACK(A1:A6,REDUCE(B1:G1,BYROW(B2:G6,LAMBDA(z,LET(a,IF(ISBLANK(z),"+",z),b,SEQUENCE(,COLUMNS(a)),c,MAP(b,LAMBDA(x,SUM(--(TAKE(a,,x)=CHOOSECOLS(a,x))))),d,IFERROR(BYROW(IFERROR(DROP(--TEXTSPLIT(TEXTJOIN("-",,a),"-","+"),-1),""),LAMBDA(y,ROUND((AVERAGE(y)),0))),0),e,IFNA(XLOOKUP(a&c,"+"&SEQUENCE(ROWS(d)),d),a),ARRAYTOTEXT(IF(e=0,XLOOKUP(b-1,b,e,0),e))))),LAMBDA(p,q,VSTACK(p,--TEXTSPLIT(q,", ")))))
Excel solution 4 for Average Fill for Blank Months, proposed by Oscar Mendez Roca Farell:
=VSTACK(A1:G1, SCAN( , A2:G6, LAMBDA(i, x, IF(x>0, x ,LET(_t, TAKE(A2:x, -1),_n, SUM(AGGREGATE(14, 6, COLUMN(_t)/(N(+_t)=0), {1,2})*{1,-1}), IFERROR(ROUND(AVERAGE(TAKE(_t, ,-_n)), ), N(i)))))))
&&&
