Using Google Sheets, I want to automatically number rows like so:
The key is that I want this to use built-in functions only.
I have an
Lol this is hilariously the longest (and very likely the most unnecessarily complicated way to combine formulas) but because I thought it was interesting that it does in fact work, so long as you just add a 1 in the first row then in the second row you add:
=if(row()=1,1,if(and(istext(D2),counta(split(A1,"."))=3),left(A1,4)&n(right(A1,1)+1),if(and(isblank(B2),isblank(C2),isblank(D2)),"",if(and(isblank(B2),isblank(C2),isnumber(indirect(address(row()-1,column())))),indirect(address(row()-1,column()))&"."&if(istext(D2),round(max(indirect(address(1,column())&":"&address(row()-1,column())))+0.1,)),if(and(isblank(B2),istext(C2)),round(max(indirect(address(1,column())&":"&address(row()-1,column())))+0.1,2),if(istext(B2),round(max(indirect(address(1,column())&":"&address(row()-1,column())))+1,),))))))
in my defense ive had a very long day at work - complicating what should be a simple thing seems to be my thing today :)
Here's an answer that does not allow a blank line between items, and requires that you manually type "1" into the first cell (A2). This formula is applied to cell A3, with the assumption that there are at most three levels of hierarchy in columns B, C, and D.
=IF(
COUNTA(B3), // If there is a value in the 1st column
INDEX(SPLIT(A2,"."),1)+1, // find the 1st part of the prior ID, plus 1
IF( // ...otherwise
COUNTA(C3), // If there's a value in the 2nd column
INDEX(SPLIT(A2,"."),1) // find the 1st part of the prior ID
& "." // add a period and
& IFERROR(INDEX(SPLIT(A2,"."),2),0)+1, // add the 2nd part of the prior ID (or 0), plus 1
INDEX(SPLIT(A2,"."),1) // ...otherwise find the 1st part of the prior ID
& "." // add a period and
& IFERROR(INDEX(SPLIT(A2,"."),2),1) // add the 2nd part of the prior ID or 1 and
& "." // add a period and
& IFERROR(INDEX(SPLIT(A2,"."),3)+1,1) // add the 3rd part of the prior ID (or 0), plus 1
)
) & "" // Ensure the result is a string ("1.2", not 1.2)
Without comments:
=IF(COUNTA(B3),INDEX(SPLIT(A2,"."),1)+1,IF(COUNTA(C3),INDEX(SPLIT(A2,"."),1)& "."& IFERROR(INDEX(SPLIT(A2,"."),2),0)+1,INDEX(SPLIT(A2,"."),1)& "."& IFERROR(INDEX(SPLIT(A2,"."),2),1)& "."& IFERROR(INDEX(SPLIT(A2,"."),3)+1,1))) & ""
Spreadsheet built-in functions doesn't include an equivalent to JavaScript .map
. The alternative is to use the spreadsheets array handling features and iteration patterns.
A "complete solution" could include the use of built-in functions to automatically transform the user input into a simple table and returning the Work Breakdown Structure number (WBS) . Some people refer to transforming the user input into a simple table as "normalization" but including this will make this post to be too long for the Stack Overflow format, so it will be focused in presenting a short formula to obtain the WBS.
It's worth to say that using formulas for doing the transformation of large data sets into a simple table as part of the continuous spreadsheet calculations, in this case, of WBS, will make the spreadsheet to slow to refresh.
To keep the WBS formula short and simple, first transform the user input into a simple table including task name, id and parent id columns, then use a formula like the following:
=ArrayFormula( IFERROR( INDEX($D$2:$D,MATCH($C2,$B$2:$B,0)) &"." &COUNTIF($C$2:$C2,C2), RANK($B2,FILTER($B$2:B,LEN($C$2:$C)=0),TRUE)&"") )
First, prepare your data
After the above steps the data should look like the following:
+---+--------------+----+-----------+ | | A | B | C | +---+--------------+----+-----------+ | 1 | Task | ID | Parent ID | | 2 | General task | 1 | | | 3 | Substast 1 | 2 | 1 | | 4 | Substast 2 | 3 | 1 | | 5 | Subsubtask 1 | 4 | 2 | | 6 | Subsubtask 2 | 5 | 2 | +---+--------------+----+-----------+
Remark: This also could help to reduce of required processing time of a custom funcion.
Second, add the below formula to D2, then fill down as needed,
=ArrayFormula( IFERROR( INDEX($D$2:$D,MATCH($C2,$B$2:$B,0)) &"." &COUNTIF($C$2:$C2,C2), RANK($B2,FILTER($B$2:B,LEN($C$2:$C)=0),TRUE)&"") )
The result should look like the following:
+---+--------------+----+-----------+----------+ | | A | B | C | D | +---+--------------+----+-----------+----------+ | 1 | Task | ID | Parent ID | WBS | | 2 | General task | 1 | | 1 | | 3 | Substast 1 | 2 | 1 | 1.1 | | 4 | Substast 2 | 3 | 1 | 1.2 | | 5 | Subsubtask 1 | 4 | 2 | 1.1.1 | | 6 | Subsubtask 2 | 5 | 2 | 1.1.2 | +---+--------------+----+-----------+----------+