Forum Discussion

VMelgarejoCaz's avatar
VMelgarejoCaz
Copper Contributor
Jan 20, 2025

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.

  • 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!

  • Patrick2788's avatar
    Patrick2788
    Silver 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
            )
        );

     

  • djclements's avatar
    djclements
    Bronze 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).

    • PeterBartholomew1's avatar
      PeterBartholomew1
      Silver 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.

      • djclements's avatar
        djclements
        Bronze 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_tarler's avatar
    m_tarler
    Bronze 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.

  • 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))))))

     

  • =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.

     

Resources