Today’s challenge is contributed by Abdelrahman Omer, MBA, PMP. List the Plan Start and End dates for all tasks based on the predecessor relationship (Finish-to-Start dependency : task’s start date is determined by the end date of its predecessor) Ex. Task 1 : Plan Start = 1-Nov (Predecessor End Date) Plan End = 1-Nov + 5 (Duration) = 6-Nov Task 2 : Plan Start = 6-Nov (late day between Task1 and Start) Plan End = 6-Nov + 2 (Duration) = 8-Nov
📌 Challenge Details and Links
ExcelBI Excel Challenge Number: 618
Challenge Difficulty: ⭐️⭐️⭐️⭐️
📥Download Sample File
📥Link to the solutions on LinkedIn
Solving the challenge of Schedule Tasks Using Dependencies with Power Query
Power Query solution 1 for Schedule Tasks Using Dependencies, proposed by Kris Jaganah:
let
A = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
B = Table.TransformColumns( A ,{"Predecessor " , each if _ = null then "Start" else _ }),
C = Table.ToColumns( B),
D = List.Zip( {C{2},C{0}}),
E = List.Positions(D),
F = List.Transform( E , (v)=> List.Sort( List.Distinct( List.Accumulate(E , {D{v}{0}} ,
(x,y)=> x& {List.Select(D, each _ {1} = List.Last( x) ){0}{0}})))),
G = List.Zip( {C{0} , C{3}}),
H = List.Transform( E ,(z) => List.Sum( List.TransformMany ( F{z} , each List.Select( G, (x)=> x{0} = _ ) , (v,w)=> w{1} )) ),
I = List.Transform(E, each [Plan Start = C{1}{0}+ hashtag#duration(H{_},0,0,0) , Plan End = #"Plan Start" + hashtag#duration(C{3}{_},0,0,0) ] ),
J = Table.FromRecords(I)
in
J
Power Query solution 2 for Schedule Tasks Using Dependencies, proposed by Aditya Kumar Darak 🇮🇳:
let
Source = Excel.CurrentWorkbook(){[Name = "data"]}[Content],
Seed = Table.AddColumn(Source, "End Date", each [Plan Start] + Duration.From([Duration])),
Records = Table.ToRecords(Seed),
Generate = List.Accumulate(
List.Skip(Records),
Seed,
(s, c) =>
[
S1 = c
& [
Plan Start = List.First(
Table.SelectRows(s, (f) => f[Task] = c[#"Predecessor "])[End Date]
)
],
S2 = S1 & [End Date = S1[Plan Start] + Duration.From(c[Duration])],
S3 = Table.ReplaceMatchingRows(s, {c, S2})
][S3]
),
Return = Generate[[Plan Start], [End Date]]
in
Return
Power Query solution 3 for Schedule Tasks Using Dependencies, proposed by Abdallah Ally:
let
Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content],
Accum = List.Accumulate(
{1 .. Table.RowCount(Source) - 1},
[a = Source{0}, b = {a & [Plan End = Date.AddDays(a[Plan Start], a[Duration])]}][b],
(s, c) =>
[
u = Source{c},
v = List.Select(s, each [Task] = u[Predecessor]){0}[Plan End],
w = u & [Plan Start = v],
x = s & {w & [Plan End = Date.AddDays(w[Plan Start], w[Duration])]}
][x]
),
FromRec = Table.FromRecords(Accum)[[Plan Start], [Plan End]],
Result = Table.TransformColumnTypes(FromRec, {{"Plan Start", type date}, {"Plan End", type date}})
in
Result
Power Query solution 4 for Schedule Tasks Using Dependencies, proposed by Seokho MOON:
let
Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content],
Rec = List.Accumulate(
{1 .. Table.RowCount(Source) - 1},
Record.AddField(
[],
Source[Task]{0},
[
Plan Start = Source[Plan Start]{0},
Plan End = Date.AddDays(#"Plan Start", Source[Duration]{0})
]
),
(a, v) =>
Record.AddField(
a,
Source[Task]{v},
[
Plan Start = Record.Field(a, Source[Predecessor]{v})[Plan End],
Plan End = Date.AddDays(#"Plan Start", Source[Duration]{v})
]
)
),
Res = Table.FromRecords(Record.ToList(Rec))
in
Res
Solving the challenge of Schedule Tasks Using Dependencies with Excel
Excel solution 1 for Schedule Tasks Using Dependencies, proposed by Bo Rydobon 🇹🇭:
=REDUCE(
B3+D3*{0,
1},
C4:C12,
LAMBDA(
a,
v,
VSTACK(
a,
INDEX(
a,
XMATCH(
v,
A3:A12
),
2
)+VLOOKUP(
v,
A3:D12,
4,
)*{0,
1}
)
)
)
=LET(
z,
A3:D12,
REDUCE(
0,
INDEX(
z,
,
3
),
LAMBDA(
a,
v,
LET(
m,
IFNA(
INDEX(
a,
XMATCH(
v,
TAKE(
z,
,
1
)
),
2
),
B3
)+{0,
1}*TAKE(
TAKE(
z,
1
):v,
-1,
-1
),
IF(
v=0,
m,
VSTACK(
a,
m
)
)
)
)
)
)
Excel solution 2 for Schedule Tasks Using Dependencies, proposed by John V.:
=REDUCE(
B3+C3:D3,
C4:C12,
LAMBDA(
a,
v,
VSTACK(
a,
XLOOKUP(
v,
DROP(
A3:v,
-1,
-2
),
DROP(
a,
,
1
)
)+N(
TAKE(
+v:D12,
1
)
)
)
)
)
Excel solution 3 for Schedule Tasks Using Dependencies, proposed by Kris Jaganah:
=LET(a,A3:A12,b,C3:C12,c,D3:D12,d,IF(b="","Start",b),e,MAP(a,LAMBDA(z,SUM(XLOOKUP(TEXTSPLIT(LET(w,LAMBDA(ME,x,LET(x,XLOOKUP(TEXTAFTER(x,",",-1,,,x),a,d),IF(RIGHT(x)="t",x,x&","&ME(ME,x)))),w(w,z)),","),a,c))))+B3,HSTACK(e,e+c))
Excel solution 4 for Schedule Tasks Using Dependencies, proposed by Kris Jaganah:
=LET(
a,
A3:A12,
b,
C3:C12,
c,
D3:D12,
d,
IF(
b="",
"Start",
b
),
e,
MAP(
a,
LAMBDA(
v,
SUM(
XLOOKUP(
UNIQUE(
SCAN(
v,
SEQUENCE(
ROWS(
a
)
),
LAMBDA(
x,
y,
XLOOKUP(
x,
a,
d
)
)
)
),
a,
c
)
)+B3
)
),
HSTACK(
e,
e+c
)
)
Excel solution 5 for Schedule Tasks Using Dependencies, proposed by Timothée BLIOT:
=LET(A,SEQUENCE(9),B,IFNA(--REGEXEXTRACT(C4:C12,"d"),0),C,D4:D12, TAKE(SORT(REDUCE({0,0,0,0,0},UNIQUE(B),LAMBDA(w,v,LET(D,TAKE(FILTER(w,TAKE(w,,1)=v),,-1),VSTACK(w,FILTER(HSTACK(A,B,C,A*0+D,C+D),B=v,"")))))),,-2)+45627)
Excel solution 6 for Schedule Tasks Using Dependencies, proposed by Md. Zohurul Islam:
=LET(
hdr,HSTACK("Plan Start","PLan End"),
std,B3,
_s1,A3:A12,
_s2,C3:C12,
_s3,D3:D12,
_s4,IF(_s2="","Start",_s2),
_s5,MAP(_s1,LAMBDA(w,LET(a,SCAN(w,SEQUENCE(ROWS(_s1)),LAMBDA(x,y,XLOOKUP(x,_s1,_s4))),b,XLOOKUP(a,_s1,_s3),c,SUM(b)+std,c))),
_s6,_s5+_s3,
_s7,HSTACK(_s5,_s6),
ans,VSTACK(hdr,_s7),
ans)
Excel solution 7 for Schedule Tasks Using Dependencies, proposed by Md. Zohurul Islam:
= 2 Then
u = Range(
"C" & x + 2
).Offset(
-2,
0
).Value
v = Application.Match(
u,
rngPred,
0
)
w = WorksheetFunction.Index(
rngEnd,
v,
1
)
PLtart = w + 0
PLend = PLtart + dr
ElseIf Right(
prd,
1
) = 1 And Right(
prdofset,
1
) <> 1 Then
u = prd
v = Application.Match(
u,
rngPred,
0
) - 1
w = WorksheetFunction.Index(
rngEnd,
v,
1
)
PLtart = w + 0
PLend = PLtart + dr
Else
u = prd
v = Application.Match(
u,
rngPred,
0
) - 1
w = WorksheetFunction.Index(
rngEnd,
v,
1
)
PLtart = w + 0
PLend = PLtart + dr
End If
'post result
Range(
"F" & x + 2
).NumberFormat = "dd-mmm"
Range(
"F" & x + 2
) = PLtart
Range(
"G" & x + 2
).NumberFormat = "dd-mmm"
Range(
"G" & x + 2
)
Excel solution 8 for Schedule Tasks Using Dependencies, proposed by Pieter de B.:
=REDUCE(
B3+D3*{0,
1},
C4:C12,
LAMBDA(
x,
y,
VSTACK(
x,
INDEX(
x,
XMATCH(
y,
A3:A12
),
2
)+INDEX(
D4:D12,
ROW(
y
)-3
)*{0,
1}
)
)
)
Excel solution 9 for Schedule Tasks Using Dependencies, proposed by Tolga Demirci, PMP, PMI-ACP, MOS-Expert:
=LET(c,LET(i,MAP(B3:B15,C3:C15,LAMBDA(m,n,IF(m<>"",m,FILTER((MAP(B3:B15,C3:C15,LAMBDA(a,b,IF(a<>"",a,FILTER((MAP(B3:B15,C3:C15,LAMBDA(i,j,IF(i<>"",i,FILTER(MAP(B3:B15,C3:C15,LAMBDA(a,b,IF(a<>"",a,FILTER(IF(C3:C15="",IF(B3:B15<>"",B3:B15,MAP(C3:C15,LAMBDA(a,FILTER(B3:B15,a=A3:A15))))+D3:D15,MAP(C3:C15,D3:D15,LAMBDA(x,y,FILTER(B3:B15,x=A3:A15)+y))),b=A3:A15))))+D3:D15,j=A3:A15)))))+D3:D15,b=A3:A15)))))+D3:D15,n=A3:A15)))),HSTACK(i,i+D3:D15)),IF(A3:A15="End",MAX(c),c))
Solving the challenge of Schedule Tasks Using Dependencies with Python
Python solution 1 for Schedule Tasks Using Dependencies, proposed by Konrad Gryczan, PhD:
import pandas as pd
from datetime import timedelta
path = "618 Project Plan with Relationship.xlsx"
input = pd.read_excel(path, usecols="A:E", skiprows=1, nrows=10)
test = pd.read_excel(path, usecols="F:G", skiprows=1, nrows=10)
input['Start'] = input.apply(lambda row: row['Plan Start'] if row['Task'] == 'Start' else pd.NaT, axis=1)
input['End'] = input['Start'] + input['Duration'].apply(lambda d: timedelta(days=d))
predecessors = input['Predecessor '].dropna().unique()
for pred in predecessors:
pred_end = input.loc[input['Task'] == pred, 'End'].values[0]
input.loc[input['Predecessor '] == pred, 'Start'] = pred_end
input['End'] = input['Start'] + input['Duration'].apply(lambda d: timedelta(days=d))
result = input[['Start', 'End']].reset_index(drop=True)
test.columns = result.columns
print(all(result == test)) # True
Solving the challenge of Schedule Tasks Using Dependencies with Python in Excel
Python in Excel solution 1 for Schedule Tasks Using Dependencies, proposed by Alejandro Campos:
from datetime import datetime, timedelta
df, start_date, task_dates = xl("A2:D12", headers=True), datetime(2024, 12, 1), {}
for _, t in df.iterrows():
ps = start_date if not t["Predecessor"] else task_dates[t["Predecessor"]]["plan_end"]
task_dates[t["Task"]] = {"plan_start": ps, "plan_end": ps + timedelta(days=t["Duration"])}
result_df = pd.DataFrame([
{k: task_dates[t["Task"]][k.replace(" ", "_").lower()].strftime('%d-%b') for k in ["Plan Start", "Plan End"]}
for _, t in df.iterrows()
])
result_df
Solving the challenge of Schedule Tasks Using Dependencies with R
R solution 1 for Schedule Tasks Using Dependencies, proposed by Konrad Gryczan, PhD:
library(tidyverse)
library(readxl)
path = "Excel/618 Project Plan with Relationship.xlsx"
input = read_excel(path, range = "A2:D12")
test = read_excel(path, range = "F2:G12")
input = input %>%
mutate(
Start = if_else(Task == "Start", `Plan Start`, as.Date(NA)),
End = if_else(Task == "Start", `Plan Start` + days(Duration), as.Date(NA))
)
predecessors = unique(input$Predecessor[!is.na(input$Predecessor)])
for (pred in predecessors) {
input = input %>%
mutate(
Start = case_when(
Predecessor == pred ~ input$End[input$Task == pred],
!is.na(Start) ~ Start,
TRUE ~ as.Date(NA)
),
End = case_when(
Predecessor == pred ~ Start + days(Duration),
!is.na(End) ~ End,
TRUE ~ as.Date(NA)
)
)
}
all.equal(test, input %>% select(Start, End), check.attributes = FALSE)
# [1] TRUE
Solving the challenge of Schedule Tasks Using Dependencies with Excel VBA
Excel VBA solution 1 for Schedule Tasks Using Dependencies, proposed by Md. Zohurul Islam:
Sub ExcelChallenge618()
Dim nx, x, u, v, w
Dim std, prd, prdofset
Dim dr, drofset
Dim PLtart, PLend
Dim rngPred As Range, rngEnd As Range
Range("F2:G2") = Array("PlanStart", "Plan End")
nx = WorksheetFunction.CountA(Range("D3:D10000"))
Set rngPred = Range("C3:C10000")
Set rngEnd = Range("G3:G10000")
std = Range("B3").Value
For x = 1 To nx
prd = Range("C" & x + 2).Value
prdofset = Range("C" & x + 2).Offset(-1, 0).Value
dr = Range("D" & x + 2).Value
drofset = Range("G" & x + 2).Offset(-1, 0).Value
'condition 01
If prd = "" And dr = 0 Then
PLtart = std
PLend = std
ElseIf prd = "Start" And dr > 0 Then
PLtart = std
PLend = std + dr
ElseIf Right(prd, 1) = 1 And prdofset = "Start" Then
PLtart = drofset
PLend = PLtart + dr
&&&
