Get the dates BEFORE and AFTER a NEW ORDER Dynamic array function allowed but Extra marks for Legacy solutions or PowerQuery Solution
📌 Challenge Details and Links
Challenge Number: 33
Challenge Difficulty: ⭐
📥Link to the solutions on LinkedIn
Solving the challenge of Get Dates Before and After a New Order with Power Query
Power Query solution 1 for Get Dates Before and After a New Order, proposed by Zoran Milokanović:
let
Source = {""} & Excel.CurrentWorkbook(){[Name = "Table1"]}[Content][SALES] & {""},
N = "NEW ORDER",
S = List.Select(
Source,
each
let
p = List.PositionOf(Source, _)
in
_ is datetime and (Source{p - 1} = N or Source{p + 1} = N)
)
in
S
Power Query solution 2 for Get Dates Before and After a New Order, proposed by Kris Jaganah:
let
Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content],
Idx = Table.AddIndexColumn(Source, "Index", 1, 1),
Select = Table.AddColumn(
Idx,
"Custom",
each Table.SelectRows(Idx, (x) => x[Index] = [Index] - 1 or x[Index] = [Index] + 1)
),
Xpand = Table.ExpandTableColumn(Select, "Custom", {"SALES"}, {"Before & After Dates"}),
Filter = Table.SelectRows(Xpand, each ([SALES] = "NEW ORDER")),
Type = Table.TransformColumnTypes(Filter, {"Before & After Dates", type date}, "en-AU"),
Keep = Table.SelectColumns(Type, {"Before & After Dates"})
in
Keep
Power Query solution 3 for Get Dates Before and After a New Order, proposed by Aditya Kumar Darak 🇮🇳:
let
Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content],
Count = Table.RowCount(Source) - 1,
Generate = List.TransformMany(
{1 .. Count},
(x) => {x - 1, x + 1},
(x, y) => if (Source[SALES]{y}? ?? null) = "NEW ORDER" then Source[SALES]{x} else null
),
Return = List.RemoveNulls(Generate)
in
Return
Power Query solution 4 for Get Dates Before and After a New Order, proposed by Alejandro Simón 🇵🇦 🇪🇸:
let
Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content],
Pos = List.PositionOf(Source[SALES], "NEW ORDER", 2),
Sol = List.Distinct(
List.Combine(
List.Transform(
Pos,
each
if _ = 0 then
{Source[SALES]{_ + 1}}
else if _ = Table.RowCount(Source) - 1 then
{Source[SALES]{_ - 1}}
else
{Source[SALES]{_ - 1}, Source[SALES]{_ + 1}}
)
)
)
in
Sol
Power Query solution 5 for Get Dates Before and After a New Order, proposed by Luan Rodrigues:
let
Fonte = Table1,
pos = List.PositionOfAny(Fonte[SALES], {"NEW ORDER"}, 2),
list = List.TransformMany(pos, each {_ - 1} & {_} & {_ + 1}, (a, b) => b),
res = Table.SelectRows(
Table.AddIndexColumn(Fonte, "ind", 0, 1),
each List.ContainsAll(list, {[ind]}) and [SALES] is datetime
)[SALES]
in
res
Power Query solution 6 for Get Dates Before and After a New Order, proposed by Brian Julius:
let
Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content],
AddAns = Table.AddColumn(
Source,
"BeforeAfterDates",
each [
b = Source[SALES],
c = List.PositionOf(b, "NEW ORDER", Occurrence.All),
d = List.Transform(c, each try b{_ - 1} otherwise null),
e = List.Transform(c, each try b{_ + 1} otherwise null),
f = List.Sort(List.RemoveNulls(List.Combine({d, e})))
][f]
),
Clean = Table.TransformColumnTypes(
Table.ExpandListColumn(
Table.FirstN(Table.RemoveColumns(AddAns, {"SALES"}), 1),
"BeforeAfterDates"
),
{"BeforeAfterDates", Date.Type}
)
in
Clean
Power Query solution 7 for Get Dates Before and After a New Order, proposed by 🇮🇷 Navid Esmaeilzadeh اسماعیل زاده:
let
Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content],
#"Added Index" = Table.AddIndexColumn(Source, "Index", 0, 1, Int64.Type),
#"Added Custom" = Table.AddColumn(
#"Added Index",
"I",
each if [SALES] = "NEW ORDER" then {[Index] + 1, [Index] - 1} else null
),
#"Expanded Date" = Table.ExpandListColumn(#"Added Custom", "I"),
#"Filtered Rows" = Table.SelectRows(#"Expanded Date", each ([I] <> null)),
#"Removed Other Columns" = Table.SelectColumns(#"Filtered Rows", {"I"}),
#"Sorted Rows" = Table.Sort(#"Removed Other Columns", {{"I", Order.Ascending}}),
#"Added Custom1" = Table.AddColumn(#"Sorted Rows", "Date", each Source[SALES]{[I]}),
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Added Custom1", {"Date"}),
#"Removed Other Columns1" = Table.SelectColumns(#"Removed Errors", {"Date"}),
#"Changed Type" = Table.TransformColumnTypes(#"Removed Other Columns1", {{"Date", type date}})
in
#"Changed Type"
Power Query solution 8 for Get Dates Before and After a New Order, proposed by Yaroslav Drohomyretskyi:
let
Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content],
Index = Table.AddIndexColumn(Source, "Index", 0, 1, Int64.Type),
Dates = Table.AddColumn(
Index,
"Before & After Dates",
each
if [SALES] = "NEW ORDER" then
{Index{[Index] - 1}[SALES], Index{[Index] + 1}[SALES]}
else
null
),
Remove = Table.SelectColumns(Dates, {"Before & After Dates"}),
Expand = Table.ExpandListColumn(Remove, "Before & After Dates"),
Errors = Table.RemoveRowsWithErrors(Expand, {"Before & After Dates"}),
NoNull = Table.SelectRows(
Errors,
each [#"Before & After Dates"] <> null and [#"Before & After Dates"] <> ""
),
Type = Table.TransformColumnTypes(NoNull, {{"Before & After Dates", type date}})
in
Type
Power Query solution 9 for Get Dates Before and After a New Order, proposed by Ahmed Ariem:
let
Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content],
types = Table.TransformColumnTypes(Source, {{"SALES", type any}}),
SelectRows = Table.SelectRows(
types,
(x) =>
List.ContainsAny(
{x[SALES]},
[
lists = List.Buffer(types[SALES]),
a = List.PositionOf(lists, "NEW ORDER", Occurrence.All),
b = List.Transform(a, (x) => lists{x - 1}),
c = List.Transform(a, (x) => lists{x + 1}? ?? null),
d = List.Sort(List.Union({b, c}))
][d]
)
)
in
SelectRows
Power Query solution 10 for Get Dates Before and After a New Order, proposed by Victor Wang:
let
Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content],
AddIndex = Table.AddIndexColumn(Source, "Index", 1, 1, Int64.Type),
FilterNewOrders = Table.SelectRows(AddIndex, each ([SALES] = "NEW ORDER")),
TransformIndex = Table.TransformColumns(
FilterNewOrders,
{{"Index", each {_ + 1, _ - 1}, type list}}
),
ExpandIndex = Table.ExpandListColumn(TransformIndex, "Index")[[Index]],
InnerJoin = Table.Join(AddIndex, {"Index"}, ExpandIndex, {"Index"})[[SALES]]
in
InnerJoin
Power Query solution 11 for Get Dates Before and After a New Order, proposed by Arnaud Duvernois:
let
Source = Excel.CurrentWorkbook(){[Name = "Tableau1"]}[Content],
Select = List.Select(
Source[SALES],
each try
Source[SALES]{List.PositionOf(Source[SALES], _) + 1}
= "NEW ORDER" or Source[SALES]{List.PositionOf(Source[SALES], _) - 1}
= "NEW ORDER"
otherwise
null
),
ToCol = Table.FromColumns({Select}, {"Before and afterdates"})
in
ToCol
Power Query solution 12 for Get Dates Before and After a New Order, proposed by Nelson Mwangi:
let
Source = Excel.CurrentWorkbook(){[Name = "Table1"]}[Content],
Ind1 = Table.AddIndexColumn(Source, "Ind1", 0, 1, Int64.Type),
Ind2 = Table.AddColumn(Ind1, "Ind2", each [Ind1] + 1, type number),
Merge1 = Table.NestedJoin(Ind2, {"Ind2"}, Ind2, {"Ind1"}, "Index2Col"),
Xpand = Table.ExpandTableColumn(Merge1, "Index2Col", {"SALES"}, {"Before"}),
Merge2 = Table.NestedJoin(Xpand, {"Ind1"}, Xpand, {"Ind2"}, "After"),
Expand = Table.ExpandTableColumn(Merge2, "After", {"SALES"}, {"After"}),
Dates = Table.AddColumn(
Expand,
"Before & After Dates",
each if [Before] = "NEW ORDER" then [SALES] else if [After] = "NEW ORDER" then [SALES] else null
)[[#"Before & After Dates"]],
Filternull = Table.SelectRows(Dates, each ([#"Before & After Dates"] <> null))
in
Filternull
Solving the challenge of Get Dates Before and After a New Order with Excel
Excel solution 1 for Get Dates Before and After a New Order, proposed by Rick Rothstein:
=DROP(
TOCOL(
FILTER(
HSTACK(
B3:B19,
B5:B21),
ISTEXT(
B4:B20))),
-1)
If it would be possible for two adjacent cells to both contain "New Order",
then this version of the above formula would be necessary...
=LET(
d,
DROP(
TOCOL(
FILTER(
HSTACK(
B3:B19,
B5:B21),
ISTEXT(
B4:B20))),
-1),
FILTER(
d,
ISNUMBER(
d)))
And,
for the purist out there who do not like my idea of the split ranges,
here are the above two formulas using only the single data range itself...
=LET(
b,
B4:B20,
DROP(
TOCOL(
FILTER(
HSTACK(
OFFSET(
b,
-1,
),
OFFSET(
b,
1,
)),
ISTEXT(
b))),
-1))
=LET(
b,
B4:B20,
d,
DROP(
TOCOL(
FILTER(
HSTACK(
OFFSET(
b,
-1,
),
OFFSET(
b,
1,
)),
ISTEXT(
b))),
-1),
FILTER(
d,
ISNUMBER(
d)))
Excel solution 2 for Get Dates Before and After a New Order, proposed by محمد حلمي:
=TOCOL(HSTACK(
B3:B20,
B5:B20)/(B4:B20>"9"),
2)
Excel solution 3 for Get Dates Before and After a New Order, proposed by 🇰🇷 Taeyong Shin:
=LET(d,
B4:B20,
TOCOL(1/(1/IFS(
d>"",
HSTACK(
VSTACK(
0,
d),
DROP(
d,
1)))),
2))
Legacy
=IFERROR(INDEX($B$1:$B$20,
AGGREGATE(15,
6,
ROW(
$B$4:$B$20)+{-1,
1}/($B$4:$B$20>""),
ROW(
A1))),
"")
Excel solution 4 for Get Dates Before and After a New Order, proposed by Kris Jaganah:
=LET(
a,
Table13[SALES],
b,
SEQUENCE(
ROWS(
a)),
TOCOL(
IFS(
a="NEW ORDER",
XLOOKUP(
b-{1,
-1},
b,
a)),
3))
Excel solution 5 for Get Dates Before and After a New Order, proposed by Julian Poeltl:
=LET(S,
B4:B20,
SS,
SEQUENCE(
ROWS(
S))*(S="NEW ORDER"),
F,
FILTER(
SS,
SS<>0),
TEXTSPLIT(
TEXTJOIN(
",",
,
MAP(
F,
LAMBDA(
A,
TEXTJOIN(
",",
,
IFERROR(
INDEX(
S,
A-1),
""),
IFERROR(
INDEX(
S,
A+1),
""))))),
,
",")*1)
Excel solution 6 for Get Dates Before and After a New Order, proposed by Aditya Kumar Darak 🇮🇳:
=TOCOL(
INDEX(
Table1[SALES],
FILTER(
SEQUENCE(
ROWS(
Table1[SALES])),
Table1[SALES] = "New Order") + {-1,
1}),
2)
Excel solution 7 for Get Dates Before and After a New Order, proposed by Oscar Mendez Roca Farell:
=TOCOL(
--REPT(
HSTACK(
B3:B19,
B5:B21),
N(
+B4:B20)=0),
2)
And my legacy solution:
=IFERROR(AGGREGATE(15,
6,
1/(N(
+B$4:B$19)*(B$5:B$20>"")+N(
+B$5:B$21)*(B$4:B$19>""))^-1,
ROW(
A1)),
"")
Excel solution 8 for Get Dates Before and After a New Order, proposed by Sunny Baggu:
=LET(
s,
Table1[SALES],
_a,
s = "NEW ORDER",
TOCOL(
INDEX(
s,
TOCOL(
SEQUENCE(
ROWS(
s)) + IF(
_a,
{-1,
1},
"x"),
3)),
3
)
)
Excel solution 9 for Get Dates Before and After a New Order, proposed by Sunny Baggu:
=LET(
s,
Table1[SALES],
c,
DROP(
s,
1) + DROP(
VSTACK(
TAKE(
s,
1),
s),
-1),
FILTER(
s,
ISERR(
c))
)
Excel solution 10 for Get Dates Before and After a New Order, proposed by Abdallah Ally:
=FILTER(B4:B20,
MAP(B4:B20,
LAMBDA(x,
(OFFSET(
x,
1,
)="NEW ORDER")+(OFFSET(
x,
-1,
)="NEW ORDER"))))
Excel solution 11 for Get Dates Before and After a New Order, proposed by Hamidi Hamid:
=LET(
x,
HSTACK(
Table1[SALES],
C3:C19)*1,
DROP(
TOCOL(
FILTER(
x,
ISERROR(
TAKE(
x,
,
1))+ISERROR(
TAKE(
x,
,
-1)),
""),
3),
1))
Excel solution 12 for Get Dates Before and After a New Order, proposed by Asheesh Pahwa:
=LET(
s,
B4:B20,
e,
s="NEW ORDER",
sq,
SEQUENCE(
ROWS(
e)),
f,
FILTER(
sq,
e),
DROP(
INDEX(
s,
DROP(
REDUCE(
"",
f,
LAMBDA(
x,
y,
VSTACK(
x,
y+{-1;1}))),
1),
),
-1))
Excel solution 13 for Get Dates Before and After a New Order, proposed by Thang Van:
=LET(
res,
MAP(
SEQUENCE(
ROWS(
Table1[SALES])),
LAMBDA(
a,
IF(
INDEX(
Table1[SALES],
a)="NEW ORDER",
TEXTJOIN(
",",
TRUE,
IFERROR(
INDEX(
Table1[SALES],
a-1),
""),
IFERROR(
INDEX(
Table1[SALES],
a+1),
""))))),
TEXTSPLIT(
TEXTJOIN(
",",
,
FILTER(
res,
res<>FALSE)),
,
","))
Excel solution 14 for Get Dates Before and After a New Order, proposed by Ankur Sharma:
=LET(
a,
MAP(
Table1[SALES],
LAMBDA(
z,
IF(
OFFSET(
z,
-1,
0) = "New Order",
z,
IF(
OFFSET(
z,
1,
0) = "New Order",
z,
"")))),
FILTER(
a,
a <> ""))
Excel solution 15 for Get Dates Before and After a New Order, proposed by Meganathan Elumalai:
=IFERROR(INDEX($B$4:$B$20,
SMALL(MODE.MULT(IFERROR((ROW(
$B$4:$B$20)-ROW(
$B$4)+1)/MATCH(
$B$4:$B$20,
{"New Order"},
{0,
0}),
""))+{-1,
1},
ROW(
INDIRECT(
"1:"&COUNTIF(
$B$4:$B$20,
"New Order")*2)))),
"")
Excel solution 16 for Get Dates Before and After a New Order, proposed by Mey Tithveasna:
=LET(
b,
B4:B20,
TOCOL(
INDEX(
b,
FILTER(
SEQUENCE(
COUNTA(
b)),
b="NEW ORDER")+{-1,
1}),
3))
Excel solution 17 for Get Dates Before and After a New Order, proposed by Milan Shrimali:
=UNIQUE(
TOCOL(
MAP(
B3:B19,
LAMBDA(
X,
if(
X="NEW ORDER",
HSTACK(
OFFSET(
X,
-1,
0),
OFFSET(
X,
1,
0)),
"")))),
0,
1)
Excel solution 18 for Get Dates Before and After a New Order, proposed by El Badlis Mohd Marzudin:
=LET(
d,
Table1[SALES],
s,
SEQUENCE(
ROWS(
d)),
DROP(
XLOOKUP(
TOCOL(
FILTER(
s,
NOT(
ISNUMBER(
d)))+{-1,
1},
3),
s,
d,
""),
-1))
Excel solution 19 for Get Dates Before and After a New Order, proposed by Miguel Angel Franco García:
=LET(
a;
ENCOL(
SI(
B4:B20=B10;
SECUENCIA(
FILAS(
B4:B20));
NOD());
3);
EXCLUIR(
INDICE(
B4:B20;
ENCOL(
APILARH(
a-1;
a+1)));
-1))
Excel solution 20 for Get Dates Before and After a New Order, proposed by Tomasz Jakóbczyk:
=IFNA(
IFS(
B5="NEW ORDER",
ROW()-3,
B3="NEW ORDER",
ROW()-3),
"")
In D4:
=INDEX(Table1[SALES],
FILTER((H4:H20),
(H4:H20)<>""),
1)
Solving the challenge of Get Dates Before and After a New Order with Python
Python solution 1 for Get Dates Before and After a New Order, proposed by Konrad Gryczan, PhD:
import pandas as pd
import numpy as np
path = "files/Excel Challenge 7th July.xlsx"
input = pd.read_excel(path, usecols="B", skiprows = 2, nrows = 17)
test = pd.read_excel(path, usecols="D", skiprows = 2, nrows = 5)
result = np.where((input["SALES"].shift() == "NEW ORDER") | (input["SALES"].shift(-1) == "NEW ORDER"), 1, 0)
result = input[result == 1].reset_index(drop=True)
result["SALES"] = result["SALES"].astype("datetime64[ns]")
print(result["SALES"].equals(test["Before & After Dates"])) # True
Solving the challenge of Get Dates Before and After a New Order with Python in Excel
Python in Excel solution 1 for Get Dates Before and After a New Order, proposed by Abdallah Ally:
df = xl("B3:B20", headers=True)
# Perform data wrangling
cond = ((df['SALES'].shift(1) == 'NEW ORDER')
+ (df['SALES'].shift(-1) == 'NEW ORDER'))
df = df[['SALES']][cond].reset_index(drop=True)
df = df.rename(columns={'SALES': 'Before & After Dates'})
df
Solving the challenge of Get Dates Before and After a New Order with R
R solution 1 for Get Dates Before and After a New Order, proposed by Konrad Gryczan, PhD:
Suprisingly short :D
library(tidyverse)
library(readxl)
path = "files/Excel Challenge 7th July.xlsx"
input = read_xlsx(path, range = "B3:B20", col_types = "date")
test = read_xlsx(path, range = "D3:D8")
result = input %>%
filter((is.na(lag(SALES)) | is.na(lead(SALES))) & (!row_number() %in% c(1, n())))
identical(result$SALES, test$`Before & After Dates`)
#> [1] TRUE
