Transpose the problem table into result table. Total Periods – Number of quarters starting with quarter given in Quarter column Every year i.e. after 4 quarters, year on year hike will be applicable as given in %Hike Yearly.
📌 Challenge Details and Links
ExcelBI Power Query Challenge Number: 183
Challenge Difficulty: ⭐️⭐️⭐️⭐️
📥Download Sample File
📥Link to the solutions on LinkedIn
Solving the challenge of Quarterly Hike Compounding Table with Power Query
Power Query solution 1 for Quarterly Hike Compounding Table, proposed by Bo Rydobon 🇹🇭:
let
Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content],
Ans = Table.Combine(
List.Transform(
Table.ToRows(Source),
(i) =>
let
q = Number.From(Text.End(i{2}, 1)) - 1
in
Table.FromRows(
List.Transform(
{q .. q + i{3} - 1},
(Q) => {
i{0},
i{1} + Number.IntegerDivide(Q, 4),
"Q" & Text.From(Number.Mod(Q, 4) + 1),
Number.Round(i{4} * Number.Power(1 + i{5} / 100, Number.IntegerDivide(Q - q, 4)))
}
),
List.FirstN(Table.ColumnNames(Source), 3) & {"Rental"}
)
)
)
in
Ans
Power Query solution 2 for Quarterly Hike Compounding Table, proposed by Zoran Milokanović:
let
Source = Excel.CurrentWorkbook(){[Name = "Input"]}[Content],
Q = {"Q1", "Q2", "Q3", "Q4"},
H = Table.ColumnNames(Source),
S = Table.FromRows(
List.TransformMany(
Table.ToRows(Source),
each {0 .. _{3} - 1},
(i, _) =>
let
c = Number.IntegerDivide(_, 4),
q = Q{Number.Mod(List.PositionOf(Q, i{2}) + _, 4)}
in
{i{0}, i{1} + c + Number.From(q < i{2}), q, Number.Power(1 + (i{5} / 100), c) * i{4}}
),
{H{0}, H{1}, H{2}, H{4}}
)
in
S
Power Query solution 3 for Quarterly Hike Compounding Table, proposed by Kris Jaganah:
let
Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
Rental = Table.AddColumn(Source, "Ans", each let
a = {1..[Total Periods]},
b =[Rental],
c =[#"% Hike Yearly"],
d = Date.EndOfQuarter( hashtag#date([Year],Number.From(Text.AfterDelimiter([Quarter],"Q"))*3,1)),
e = List.Transform(a, each let
p = Number.Round( Number.Power( (1+c/100),Number.IntegerDivide(_-1,4)) * b ,0),
q= Date.AddQuarters(d,_ -1 ),
r = Text.From(Date.Year(q)),
s = "Q"& Text.From( Date.QuarterOfYear(q)) ,
t = r&"-"&s&"-"& Text.From( p) in t ),
f = Table.FromList(e,Splitter.SplitTextByDelimiter("-"), {"Year", "Quarter", "Rental"})
in f),
Select = Table.SelectColumns(Rental,{"Vendor", "Ans"}),
Xpand = Table.ExpandTableColumn(Select, "Ans", {"Year", "Quarter", "Rental"}),
Changetype = Table.TransformColumnTypes(Xpand,{{"Year", Int64.Type}, {"Rental", Int64.Type}})
in
Changetype
Power Query solution 4 for Quarterly Hike Compounding Table, proposed by Aditya Kumar Darak 🇮🇳:
let
Source = Excel.CurrentWorkbook(){[Name = "data"]}[Content],
Qtrs = List.Transform({"1" .. "4", "1" .. "4"}, each "Q" & _),
Record = Table.AddColumn(
Source,
"R",
each [
P = List.PositionOf(Qtrs, [Quarter]),
G = List.Generate(
() => [a = 0, Q = [Quarter], Y = [Year], R = [Rental]],
(f) => f[a] < [Total Periods],
(f) => [
a = f[a] + 1,
M = Number.Mod(a, 4),
Q = Qtrs{M + P},
Y = f[Y] + Number.From(Q = "Q1"),
R = f[R] * (1 + [#"% Hike Yearly"] * Number.From(M = 0) / 100)
],
(f) => [Vendor = [Vendor], Year = f[Y], Quarter = f[Q], Rental = Number.Round(f[R])]
)
][G]
),
Return = Table.FromRecords(List.Combine(Record[R]))
in
Return
Power Query solution 5 for Quarterly Hike Compounding Table, proposed by Alejandro Simón 🇵🇦 🇪🇸:
let
Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content],
Group = Table.Group(
Source,
{"Vendor"},
{
{
"A",
(x) =>
let
b = List.Repeat({1 .. 4}, Number.RoundUp(x[Total Periods]{0} / 4) + 1),
c = List.Transform(
List.FirstN(
List.Skip(b, Number.From(Text.End(x[Quarter]{0}, 1)) - 1),
x[Total Periods]{0}
),
each "Q" & Text.From(_)
),
d = List.Skip(
List.Generate(
() => [y = 0, z = x[Year]{0}],
each [y] <= List.Count(b),
each [
y = [y] + 1,
z = if try b{[y]} = b{[y] - 1} + 1 otherwise true then [z] else [z] + 1
],
each [z]
)
),
e = List.FirstN(
List.Skip(d, Number.From(Text.End(x[Quarter]{0}, 1)) - 1),
x[Total Periods]{0}
),
f = List.Transform({0 .. x[Total Periods]{0} - 1}, each Number.IntegerDivide(_, 4) + 1),
g = List.FirstN(
List.Skip(
List.Generate(
() => [y = 0, z = x[Rental]{0}],
each [y] <= List.Count(b),
each [
y = [y] + 1,
z =
if try f{[y]} = f{[y] - 1} otherwise true then
[z]
else
[z] * (1 + x[#"% Hike Yearly"]{0} / 100)
],
each [z]
)
),
x[Total Periods]{0}
),
h = Table.FromColumns({e, c, g}, {"Year", "Quarter", "Rental"})
in
h
}
}
),
Sol = Table.ExpandTableColumn(Group, "A", Table.ColumnNames(Group[A]{0}))
in
Sol
Power Query solution 6 for Quarterly Hike Compounding Table, proposed by Hussein SATOUR:
let
Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
AddCust = Table.AddColumn(Source, "Custom", each let
a = Number.From(Text.End([Quarter],1)) * 3,
b = hashtag#date([Year], a, 1),
c = List.Transform({0 .. [Total Periods]-1}, (x)=> Date.AddQuarters(b, x)),
d = List.Transform(c, (x)=> Number.RoundDown(Duration.Days(x - b)/365))
in List.Zip({c,d})),
ExpandCust = Table.ExpandListColumn(AddCust, "Custom"),
ExtractVals = Table.TransformColumns(ExpandCust, {"Custom", each Text.Combine(List.Transform(_, Text.From), " ")}),
Split = Table.SplitColumn(ExtractVals, "Custom", Splitter.SplitTextByDelimiter(" ", QuoteStyle.Csv), {"Quarters", "Custom.2"}),
ChangType = Table.TransformColumnTypes(Split,{{"Quarters", type date}, {"Custom.2", Int64.Type}}),
AddRentals = Table.AddColumn(ChangType, "Rentals", each Number.Power(1 + ([#"% Hike Yearly"]/100), [Custom.2]) * [Rental]),
CalculatQuarter = Table.TransformColumns(AddRentals,{{"Quarters", each "Q" & Text.From(Date.QuarterOfYear(_))}}),
RemoveOthers = Table.SelectColumns(CalculatQuarter,{"Vendor", "Year", "Quarters", "Rentals"})
in RemoveOthers
Power Query solution 7 for Quarterly Hike Compounding Table, proposed by Alexis Olson:
let
Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
AddCol = Table.AddColumn(Source, "Table", each
[
Periods = {1..[Total Periods]},
YearQtr = Date.EndOfMonth(hashtag#date([Year], 3 * Number.From(Text.End([Quarter], 1)), 1)),
Quarters = List.Transform(Periods, (i) => Date.AddQuarters(YearQtr, i - 1)),
Rental = List.Transform(Periods, (i) => [Rental] * Number.Power(1 + [#"% Hike Yearly"] / 100, Number.IntegerDivide(i - 1, 4))),
Table = Table.FromColumns({Quarters, Rental}, {"QtrEnd", "Rental"})
][Table]
),
SelectCols = Table.SelectColumns(AddCol,{"Vendor", "Table"}),
ExpandTable = Table.ExpandTableColumn(SelectCols, "Table", {"QtrEnd", "Rental"}),
YearQtr = Table.ReplaceValue(ExpandTable, each [QtrEnd], each [Year = Date.Year([QtrEnd]), Quarter = "Q" & Text.From(Date.QuarterOfYear([QtrEnd]))], Replacer.ReplaceValue, {"QtrEnd"}),
ExpandRecord = Table.ExpandRecordColumn(YearQtr, "QtrEnd", {"Year", "Quarter"}, {"Year", "Quarter"})
in
ExpandRecord
Power Query solution 8 for Quarterly Hike Compounding Table, proposed by Ramiro Ayala Chávez:
let
S = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content],
L = List.Transform,
A = Table.AddColumn,
T = Table.TransformColumns,
Y = Table.TransformColumnTypes,
R = Number.Round,
TS = Text.StartsWith,
N = Table.ColumnNames,
a = Table.SplitColumn(S, "Quarter", Splitter.SplitTextByRepeatedLengths(1), {"Q1", "Q2"}),
b = Y(a, {"Q2", Int64.Type}),
c = A(b, "L", each [Q2] + [Total Periods] - 1),
d = A(c, "Q", each {[Q2] .. [L]}),
e = Table.ExpandListColumn(d, "Q")[[Vendor], [Year], [Rental], [#"% Hike Yearly"], [Q]],
f = A(e, "Y1", each if [Q] > 4 then [Year] + 1 else [Year]),
g = A(f, "Y2", each if [Q] > 8 then [Y1] + 1 else [Y1])[
[Vendor],
[Rental],
[#"% Hike Yearly"],
[Q],
[Y2]
],
h = L(Table.Group(g, {"Vendor"}, {"G", each _})[G], each Table.AddIndexColumn(_, "I")),
i = L(
h,
each A(
_,
"R1",
each if [I] > 3 then R([#"% Hike Yearly"] / 100 * [Rental] + [Rental]) else R([Rental])
)
),
j = L(
i,
each A(_, "R2", each if [I] > 7 then R([#"% Hike Yearly"] / 100 * [R1] + [R1]) else R([R1]))
),
k = Table.Combine(j)[[Vendor], [Y2], [R2], [Q]],
l = A(k, "Q1", each if [Q] > 4 then [Q] - 4 else [Q]),
m = A(l, "Q2", each if [Q1] > 4 then [Q1] - 4 else [Q1]),
n = T(Y(m, {{"Q2", type text}}), {"Q2", each "Q" & _})[[Vendor], [Y2], [Q2], [R2]],
o = List.Select(N(S), each not TS(_, "T") and not TS(_, "%")),
Sol = Table.RenameColumns(n, List.Zip({N(n), o}))
in
Sol
Power Query solution 9 for Quarterly Hike Compounding Table, proposed by Eric Laforce:
let
Source = Excel.CurrentWorkbook(){[Name="tData183"]}[Content],
TransformRows = List.Transform(Table.ToRecords(Source), (r)=> let
_DStart = Date.StartOfQuarter(hashtag#date(r[Year],3*Number.From(Text.End(r[Quarter],1)),1)),
_IncY = 1 + (r[#"% Hike Yearly"] / 100)
in List.Transform({0..r[Total Periods]-1}, each let
_Date = Date.AddQuarters(_DStart, _),
_R = Number.Round(r[Rental] * Number.Power(_IncY, Number.IntegerDivide(_,4)))
in {r[Vendor], Date.Year(_Date), "Q" & Text.From(Date.QuarterOfYear(_Date)), _R} ) ),
Result = Table.FromRows(List.Combine(TransformRows), {"Vendor", "Year", "Quater", "Rental"})
in
Result
Power Query solution 10 for Quarterly Hike Compounding Table, proposed by Peter Tholstrup:
let
Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content],
f = (t) =>
List.Generate(
() => [i = 1, Y = t[Year], Q = t[Quarter], R = t[Rental]],
each [i] <= t[Total Periods],
each [
c = Number.From(Text.End([Q], 1)),
y = if c = 4 then [Y] + 1 else [Y],
q = "Q" & Text.From(if c = 4 then 1 else c + 1),
m = Number.Power(1 + t[#"% Hike Yearly"] / 100, Number.IntegerDivide([i], 4)),
result = [i = [i] + 1, Y = y, Q = q, R = Number.Round(t[Rental] * m, 0)]
][result],
each [Vendor = t[Vendor], Year = [Y], Quarter = [Q], Rental = [R]]
),
result = Table.FromRecords(List.Combine(Table.TransformRows(Source, f)))
in
result
Solving the challenge of Quarterly Hike Compounding Table with Excel
Excel solution 1 for Quarterly Hike Compounding Table, proposed by Bo Rydobon 🇹🇭:
=REDUCE(H1:K1,A2:A5,LAMBDA(a,v,LET(i,LAMBDA(x,INDEX(v:F5,1,x)),
q,SEQUENCE(i(4),,RIGHT(i(3))-1),IFNA(VSTACK(a,HSTACK(v,i(2)+INT(q/4),"Q"&MOD(q,4)+1,ROUND(i(5)*(1+i(6)%)^(INT((q-@q)/4)),))),v))))
Excel solution 2 for Quarterly Hike Compounding Table, proposed by محمد حلمي:
=REDUCE(H1:K1,A2:A5,LAMBDA(a,v,VSTACK(a,LET(
j,LAMBDA(x,OFFSET(v,,x)),u,SEQUENCE(j(3))-1,
s,u+RIGHT(j(2))-1,HSTACK(IF(u+1,v),INT(s/4)+j(1),
"Q"&MOD(s,4)+1,ROUND(j(4)*(1+j(5)%)^INT(u/4),))))))
Excel solution 3 for Quarterly Hike Compounding Table, proposed by Julian Poeltl:
=LET(T,A2:F5,V,TAKE(T,,1),Y,CHOOSECOLS(T,2),Q,CHOOSECOLS(T,3),TP,CHOOSECOLS(T,4),R,CHOOSECOLS(T,5),H,TAKE(T,,-1),RTP,SCAN(,TP,LAMBDA(A,B,A+B)),BT,RTP-TP+1,AR,MAKEARRAY(MAX(RTP),3,LAMBDA(A,B,IFS(B=1,XLOOKUP(A,RTP,V,,1),B=2,XLOOKUP(A,BT,Y,0),B=3,XLOOKUP(A,BT,Q,0)))),QQ,SCAN(,CHOOSECOLS(AR,3),LAMBDA(A,B,IF(B<>0,B,SWITCH(A,"Q1","Q2","Q2","Q3","Q3","Q4","Q4","Q1")))),YY,SCAN(,CHOOSECOLS(AR,2),LAMBDA(A,B,IF(B=0,A,B))),YC,IF(TAKE(AR,,1)=VSTACK(TAKE(V,1),DROP(TAKE(AR,,1),-1)),IF(QQ="Q1",1,0),0),YYY,YY+LEFT(SCAN(,YC&TAKE(AR,,1),LAMBDA(A,B,IF(RIGHT(B)=RIGHT(A),(LEFT(B)+LEFT(A))&RIGHT(B),B)))),RH,MAKEARRAY(MAX(RTP),1,LAMBDA(A,B,XLOOKUP(A,RTP,H,,1))),RT,ROUNDDOWN((SCAN(,--(DROP(VSTACK(TAKE(V,1),TAKE(AR,,1)),-1)=TAKE(AR,,1)),LAMBDA(A,B,IF(B=1,A+1,1)))-1)/4,0),Rent,XLOOKUP(SEQUENCE(MAX(RTP)),RTP,R,,1)*(1+XLOOKUP(SEQUENCE(MAX(RTP)),RTP,H,,1)/100)^RT,VSTACK(HSTACK("Vendor","Year","Quarter","Rental"),HSTACK(TAKE(AR,,1),YYY,QQ,Rent)))
Excel solution 4 for Quarterly Hike Compounding Table, proposed by Sunny Baggu:
=LET(
z, A2:F5,
REDUCE(
HSTACK(A1:C1, E1),
SEQUENCE(ROWS(z)),
LAMBDA(x, y,
VSTACK(
x,
LET(
_s, SEQUENCE(INDEX(z, y, 4)),
_n, --RIGHT(INDEX(z, y, 3), 1),
_s1, _n + _s - 1,
_y1, ROUNDUP(_s1 / 4, 0) - 1,
_v, IF(_s, INDEX(z, y, 1)),
_y2, _y1 + INDEX(z, y, 2),
_q, "Q" & (_s1 - 4 * _y1),
_r, INDEX(z, y, 5) *
SCAN(
1,
DROP(VSTACK(0, N(MOD(_s, 4) = 0)), -1),
LAMBDA(a, v, IF(v = 1, (INDEX(z, y, 6) / 100 + 1) * a, a))
),
HSTACK(_v, _y2, _q, _r)
)
)
)
)
)
Excel solution 5 for Quarterly Hike Compounding Table, proposed by LEONARD OCHEA 🇷🇴:
=REDUCE(H1:K1,A2:A5,LAMBDA(a,v,LET(d,LAMBDA(x,OFFSET(v,,x)),s,SEQUENCE(d(3)),n,s+RIGHT(d(2))-2,VSTACK(a,HSTACK(IF(s,v),d(1)+INT(n/4),"Q"&MOD(n,4)+1,d(4)*(1+d(5)%)^INT((s-1)/4))))))
Excel solution 6 for Quarterly Hike Compounding Table, proposed by Abdallah Ally:
=REDUCE({"Vendor","Year","Quarter","Rental"},D2:D5,LAMBDA(x,y, VSTACK(x,REDUCE(HSTACK(OFFSET(y,,-3,,3),OFFSET(y,,1)),SEQUENCE(y-1),LAMBDA(u,v,LET(r,--RIGHT(OFFSET(y,,-1)),s,r+v,VSTACK(u, HSTACK(OFFSET(y,,-3),OFFSET(y,,-2)+IF(MOD(s,4)=0,INT(s/4)-1,INT(s/4)),IF(MOD(s,4)=0,"Q4","Q"&MOD(s,4)),ROUND(IFS(v=1,OFFSET(y,,1),MOD(v,4)=0,(1+OFFSET(y,,2)/100)*TAKE(u,-1,-1),1,TAKE(u,-1,-1)),0)))))))))
Excel solution 7 for Quarterly Hike Compounding Table, proposed by Burhan Cesur:
=REDUCE(H1:K1,A2:A5,LAMBDA(s,v,
VSTACK(s,LET(f,LAMBDA(x,OFFSET(v,,x)),z,--RIGHT(f(2),1),y,INT(SEQUENCE(f(3),,z-1)/4),e,IF(y+f(1),v),t,1+MOD(SEQUENCE(f(3),,z-1),4),q,SCAN(f(4),VSTACK(0,DROP("Q"&t,1)),LAMBDA(acc,val,IF(val=f(2),acc*(1+f(5)%),acc))),
HSTACK(e,f(1)+y,"Q"&t,q)))))
Solving the challenge of Quarterly Hike Compounding Table with Python in Excel
Python in Exce&l solution 1 for Quarterly Hike Compounding Table, proposed by Abdallah Ally:
import pandas as pd
file_path = 'PQ_Challenge_183.xlsx'
df = pd.read_excel(file_path, usecols='A:F', nrows=4)
df1 = pd.read_excel(file_path, usecols='H:K') # Expected
df1.iloc[:, 3] = df1.iloc[:, 3].map(lambda x: round(x))
# Perform data wrangling
items = []
for i in df.index:
v, h, r = df.iloc[i, [0, 5, 4]]
for j in range(df.iat[i, 3]):
y, q = df.iloc[i, [1, 2]]
n = j + int(q[1])
if n <= 4:
items.append([v, y, 'Q' + str(n), r])
else:
y = df.iat[i, 1] + (n // 4 - 1 if n % 4 == 0 else n // 4)
q = 'Q4' if n % 4 == 0 else 'Q' + str(n % 4)
r = r * (1 + h / 100) if j % 4 == 0 else r
items.append([v, y, q, r])
df = pd.DataFrame(items, columns=df.columns[[0, 1, 2, 4]]) # Computed
df['Rental'] = df['Rental'].map(lambda x: round(x))
print(f'nMy Results vs Expected Results! Equal? {(df.values == df1.values).all()}')
# Display sample results
df.sample(10)
Solving the challenge of Quarterly Hike Compounding Table with R
R solution 1 for Quarterly Hike Compounding Table, proposed by Konrad Gryczan, PhD:
library(tidyverse)
library(readxl)
input = read_excel("Power Query/PQ_Challenge_183.xlsx", range = "A1:F5")
test = read_excel("Power Query/PQ_Challenge_183.xlsx", range = "H1:K24") %>%
mutate(Rental = as.integer(Rental))
result = input %>%
unite("OYQ", Year, Quarter, sep = " ") %>%
mutate(OYQ = yq(OYQ)) %>%
rowwise() %>%
mutate(quarters = list(seq.Date(from = as.Date(OYQ), by = "quarter", length.out = `Total Periods`))) %>%
ungroup() %>%
unnest(quarters) %>%
mutate(Year = year(quarters),
Quarter = paste0("Q",quarter(quarters)),
rn = row_number(),
roll_year = (rn - 1) %/% 4 ,
.by = Vendor) %>%
mutate(Rental = round(Rental * (1 + `% Hike Yearly`/100)^roll_year) %>% as.integer()) %>%
select(Vendor, Year, Quarter, Rental)
identical(result, test)
# [1] TRUE
&&
