google-sheetsgoogle-sheets-formula

How can I stack each 3 sets of 4 rows?


I have a report that vertically stacks yearly data made of two columns:

  1. The first column shows the year and each of its 4 quarters (format: "YYYY Qx").
  2. The second column shows a $ amount.

A year is made of 4 rows corresponding to 4 quarters. As the reports vertically stacks data every year, 4 new rows are added every new year.

I would like to horizontally stack each 3 sets (2022, 2023 and 2024) of 4 rows with adjacent column #2 data. The result is a table of 4 rows and 3*2=6 columns.

Start table in cell A1:

YEAR & QUARTER $ AMOUNT
2022 Q1 1000
2022 Q2 2000
2022 Q3 3000
2022 Q4 4000
2023 Q1 500
2023 Q2 1000
2023 Q3 800
2023 Q4 1500
2024 Q1 1500
2024 Q2 2000
2024 Q3 3000
2024 Q4 4500

Desired output:

2023 $ AMOUNT 2024 $ AMOUNT 2025 $ AMOUNT
2022 Q1 1000 2023 Q1 500 2024 Q1 1500
2022 Q2 2000 2023 Q2 1000 2024 Q2 2000
2022 Q3 3000 2023 Q3 800 2024 Q3 3000
2022 Q4 4000 2023 Q4 1500 2024 Q4 4500

I do not need to generate the header row. I thought it would be simple:

=wraprows(tocol(A2:B13);8)

I still cannot make it:

=wrapcols(torow(wrapcols(torow(A2:B13);2));4)

I would join the two columns and wrap the result but how do I split later on?

=let(
list1;byrow(A1:B12;lambda(x;join("|";x)));
wrapcols(list1;4)
)

Solution

  • One way is to use Makearray. You move down four rows in the input each time you move across to the next pair of columns in the output, and for odd columns of the output take input from the left-hand column, or for even columns of the output take input from the right-hand column.

    =makearray(4,6,lambda(r,c,index(A1:B12,r+4*quotient(c-1,2),iseven(c)+1)))
    
    Input Output
    A1 11 A1 11 B1 21 C1 31
    A2 12 A2 12 B2 22 C2 32
    A3 13 A3 13 B3 23 C3 33
    A4 14 A4 14 B4 24 C4 34
    B1 21
    B2 22
    B3 23
    B4 24
    C1 31
    C2 32
    C3 33
    C4 34

    A more general form of the formula where you could adjust rows and columns would be (for three columns of input and nine columns of output)

    =makearray(4,9,lambda(r,c,index(A15:C26,r+4*quotient(c-1,3),mod(c-1,3)+1)))
    

    If you wanted to make the formula even more general, but assuming for now that the data divides exactly by the required number of columns , you could try this:

    =let(range,A2:B13,inCols,columns(range),inRows,rows(range),reps,3,outRows,inRows/reps,outCols,inCols*reps,makearray(outRows,outCols,lambda(r,c,index(range,r+inRows/reps*quotient(c-1,inCols),mod(c-1,inCols)+1))))
    

    Or for the case where the data doesn't divide exactly into the required number of columns,

    =let(range,A2:B12,inCols,columns(range),inRows,rows(range),reps,3,outRows,roundup(inRows/reps),outCols,inCols*reps,iferror(makearray(outRows,outCols,lambda(r,c,index(range,r+outRows*quotient(c-1,inCols),mod(c-1,inCols)+1)))))
    

    Maybe this is nearer to OP's requirement, where the number of rows of output is fixed (four quarters per column) and the number of columns is adjusted to match the number of rows of data provided.

    =let(range,A2:B13,inCols,columns(range),inRows,rows(range),outRows,4,outCols,roundup(inRows/outRows)*inCols,iferror(makearray(outRows,outCols,lambda(r,c,index(range,r+outRows*quotient(c-1,inCols),mod(c-1,inCols)+1)))))