Forum Discussion
VMelgarejoCaz
Jan 20, 2025Copper Contributor
Transpose in arrays of n columns
Hello all and thanks in adhance for your help.
I am tryting to find a formula or shortcut that would allow me to transpose arrays of n columns into matrixes of n rows and n columns, to plot the data in a different software.
In this example I have two arrays, each is 3x3:
The software where I need to plot, asks for three arrays of 2x3 as shown:
In reality I'm working with three different softwares, the first one gives me raw data that I compute in Excel, obtaining up to 56 groups as shown in the first picture; however, the third software requests the data as the structure shown in the second picture.
Any suggestions are welcome.
- PeterBartholomew1Silver Contributor
A nice piece of work! To my mind this is an example of Excel formulas as they should be.
A million miles from the traditional spreadsheet!
- Patrick2788Silver Contributor
This solution is from a past discussion concerning Thunks.
=ReShapeMatrixλ(data, 3, 3)
ReShapeMatrixλ gets an assist from Peter's EVALTHUNKARRλ -
//Re-shape a matrix by specifying width and depth. 'shape' - 0 to vertically stack arrays, //1 to horizontally stack arrays. 'shape' defaults to vertical stack if omitted. //'pad_with' defaults to "" if omitted. ReShapeMatrixλ = LAMBDA(matrix, depth, width, [shape], [pad_with], LET( //Prevent uneven distribution of rows and/or columns by //ensuring dimensions are properly rounded according to //depth and width. i, CEILING.MATH(ROWS(matrix), depth), j, CEILING.MATH(COLUMNS(matrix), width), //Set padding and expand matrix as needed. padding, IF(ISOMITTED(pad_with), "", pad_with), M, EXPAND(matrix, i, j, padding), //Create two matrices which serve as row and column coordinates //for INDEX. M_rows, SEQUENCE(i / depth, , , depth) * SEQUENCE(, j / width, , 0), M_cols, SEQUENCE(, j / width, , width) * SEQUENCE(i / depth, , , 0), //Generate 'r' and 'c' coordinates based on starting row (v₁) and column (v₂). //Retrieve 'block' from matrix as a vector and stuff in a thunk. CreateVectors, LAMBDA(v₁, v₂, LET( r, TOCOL(SEQUENCE(depth, , v₁) * SEQUENCE(, width, , 0)), c, TOCOL(SEQUENCE(, width, v₂) * SEQUENCE(depth, , , 0)), block, INDEX(M, r, c), THUNK(block) ) ), //Map and convert to vector to prepare for unpacking. thunks, TOCOL(MAP(M_rows, M_cols, CreateVectors)), //Unpack thunks. unpacked, EVALTHUNKARRλ(thunks), //Wrap vector according to desired shape. vshaped, WRAPROWS(unpacked, depth * width), hshaped, WRAPCOLS(unpacked, depth * width), reshaped, IF( ISOMITTED(shape), vshaped, IF(shape, hshaped, vshaped) ), reshaped ) );
- djclementsBronze Contributor
Another potential option, using TRANSPOSE and PIVOTBY, plus a few extra steps to sort the results and rearrange the header rows:
=LET( arr, TRANSPOSE(A1:G5), pvt, DROP(PIVOTBY(SCAN("",TAKE(arr,,1),LAMBDA(a,v,IF(v="",a,v))),INDEX(arr,,2),DROP(arr,,2),SUM,3,0,,0,-1),1), srt, SORTBY(pvt,INDEX(pvt,2)), grp, INDEX(srt,2), VSTACK(IF(grp<>HSTACK("",DROP(grp,,-1)),"Group "&grp,""),TAKE(srt,1),DROP(srt,2)) )
Note: the SCAN function used in the row_fields argument of PIVOTBY assumes the "Grade" headers shown in your raw data screenshot have Merge & Center formatting applied (they appear to, considering the vertical gridlines are not visible).
- PeterBartholomew1Silver Contributor
We have a really interesting set of alternatives here, each with pros and cons.
David. I didn't understand how you got PIVOTBY to work without much more in the way of preliminary work normalising the crosstab, so I added code to step through your solution. I hadn't realised that PIVOTBY would work with multiple fields.
If anything I think your solution is probably the best but it was not a one horse race! The image below is my 'test environment' (if only it were quicker to set up).
My apologies for the minor code changes.
- djclementsBronze Contributor
No worries, Peter. And thank you for providing the step-by-step walkthrough. "Best" is very much a subjective term in this game, so I'm not too worried about that. ;) One of my primary goals over the past year and a half or more has been to discover and share efficient alternatives to the generic DROP-REDUCE-STACK method. GROUPBY and PIVOTBY have been a game changer in that regards, eliminating the need for complex intermediary steps in many cases. I had previously used GROUPBY with multiple value fields, but this was my first time trying it with PIVOTBY. It worked out well!
- m_tarlerBronze Contributor
I throw another option into the ring. I was about to add it when I saw Peter dropped his so I used his workbook and combined all 3 on this workbook.
This option is:
=LET(in, B3:M7, cols, 3, DROP(REDUCE("",SEQUENCE(ROWS(in)), LAMBDA(p,q,HSTACK(p,WRAPROWS(CHOOSEROWS(in,q),cols,0)))),,1))
simply each ROW uses WRAPROWS to create the columns needed and stack to the right.
- PeterBartholomew1Silver Contributor
This formula uses a complicated function to expand thunks. Otherwise switching the order of the dimensions in a multidimensional array requires sorting by index.
= EVALTHUNKARRλ(TRANSPOSE(BYROW(rng, LAMBDA(d, LAMBDA(WRAPROWS(d, cols))))))
- OliverScheurichGold Contributor
=LET(cols,3,
rng,B3:M7,
DROP(REDUCE("",SEQUENCE(1,COLUMNS(rng)/cols,1,cols),
LAMBDA(u,v,
VSTACK(u,
TOROW(CHOOSECOLS(rng,SEQUENCE(1,cols,v)))))),
1)
)
This formula works in Office 365 and Excel for the web and returns the intended result in my example. You dynamically change the number of columns in the formula.