As with most APL symbols, has different meanings when called with one argument (transpose) versus two arguments (dyadic transpose / reorder dimensions). This challenge concerns the latter, which acts similarly to numpy.moveaxis in Python or permute in MATLAB, but is more powerful.

order ⍉ A when order has distinct entries

When all members of order are distinct, order ⍉ A is equivalent to:

  • numpy.moveaxis(A, tuple(range(len(A.shape)), order) in Python, or
  • permute(A,order) in MATLAB. Quoting from documentation of the latter:

B = permute(A,order) rearranges the dimensions of A so that they are in the order specified by the vector order. The resulting array B has the same values as A but the order of the subscripts needed to access any particular element is rearranged as specified by order.

For example, suppose A is a 3D array, and let B ← (2 0 1)⍉A. Then B is such that B[x0,x1,x2] = A[x2,x0,x1] for all x2,x0,x1

order ⍉ A when order has repeated entries

When order has repeated entries, we take a diagonal slice of the array. For example, let A be a 2x3x4 array. B ← (0 0 1)⍉A takes a diagonal slice along A to create B such that B[x0,x1] = A[x0,x0,x1]. Note that B is a 2x4 array: if it were 3x4, we would need to set B[2, x1] = A[2, 2, x1] which would be out of bounds of A. In general the kth dimension of B will be the minimum of all A.shape[i] such that order[i] = k.

Example

Consider the dyadic transpose order⍉A where order = [2, 1, 0] and A is 3x4x5

    A =
[[[ 0  1  2  3  4]
  [ 5  6  7  8  9]
  [10 11 12 13 14]
  [15 16 17 18 19]]

 [[20 21 22 23 24]
  [25 26 27 28 29]
  [30 31 32 33 34]
  [35 36 37 38 39]]

 [[40 41 42 43 44]
  [45 46 47 48 49]
  [50 51 52 53 54]
  [55 56 57 58 59]]]

The result is the 5x4x3 array B =

[[[ 0 20 40]
  [ 5 25 45]
  [10 30 50]
  [15 35 55]]

 [[ 1 21 41]
  [ 6 26 46]
  [11 31 51]
  [16 36 56]]

 [[ 2 22 42]
  [ 7 27 47]
  [12 32 52]
  [17 37 57]]

 [[ 3 23 43]
  [ 8 28 48]
  [13 33 53]
  [18 38 58]]

 [[ 4 24 44]
  [ 9 29 49]
  [14 34 54]
  [19 39 59]]]

Note that when, for example, (x0, x1, x2) = (4,1,2) we have B[x0,x1,x2] = A[x2, x1, x0] = A[2,1,4] = 49.

If instead order = [0, 0, 0] and A as above, then we would have the output B be the 1-dimensional size-3 array B = [0, 26, 52] so that B[1] = B[x0] = A[x0,x0,x0] = A[1,1,1] = 26

Input

Here we use 0-indexing, but you may also use 1-indexing as is the APL default.

  • A multidimensional or nested array A, of dimension n ≥ 1.

  • A list order of n positive integers consisting of the integers {0,1,...,k} (or {1,...,k+1} for 1-index) for some k < n, in any order, possibly with repetitions.

Output

  • A multidimensional or nested array representing the result of applying the dyadic transpose with those arguments. (The output will have dimension k+1.)

You may write a full program, function, etc. as allowed by the current standard on meta.

If your language has a builtin, it is encouraged to also write a solution without the builtin for the sake of an interesting answer.

Test cases

Test cases on TIO

Reference Python implementation coming soon.

Note for reading test cases: in APL, the penultimate and ultimate axes of an array are along columns and rows in that order.

  • 3
    APL, 1 byte: :P – Quintec Nov 17 at 23:01
  • Actually, many APL symbols just use a default second argument when called with one argument. This includes which uses the reversed axis indices as default, so ⍉A is the same as (2 1 0)⍉A if A is a 3-dimensional array and in general ⍉A is (⌽⍳≢⍴A)⍉A. – Adám Nov 18 at 10:04
  • @lirtosiast question about i/o: can a multidimensional array be represented as a pair of shape (list of dimensions) and content (all elements in lexicographical order of their indices)? – ngn Nov 19 at 13:26
  • @ngn I would say no for now, but you should ask on meta whether that format is acceptable by default. – lirtosiast Nov 19 at 18:55
  • @lirtosiast Anecdotally, Dyalog APL internally stores arrays as [number-of-dimensions,first-dimension-length,second-dimension-length,…,last-dimension-length,first-element,second-element,…,last-element]. – Adám Nov 19 at 19:15

APL (Dyalog Unicode), 34 bytesSBCS

This is my colleague's code (slightly modified from Roger Hui: A History of APL in 50 Functions, chapter 30), posted with explicit permission.

Anonymous tacit infix lambda (can be used as drop-in for ).

{⍵[(⊂⊂⍺)⌷¨,¨⍳⍺[⍋⍺]{⌊/⍵}⌸(⍴⍵)[⍋⍺]]}

Try it online!

{} dfn; is left argument (axes), is right argument (array)
E.g. [2,2,1] and [[[1,2],[3,4]]]

⍵[] index the array with:

  (⍴⍵)[] the shape (lengths of axes) of the array, indexed by:
  [1,2,2]

   ⍋⍺ the grading vector (the indices that would sort them) of the axes
   [3,1,2]
  [2,1,2]

  ⍺[⍋⍺]{}⌸ use the sorted axes as keys to group that, and for each group:
  [1,2,2]{"1":[2],"2":[1,2]}

   {⌊/⍵} find the lowest axis length
   {"1":2,"2":1}[2,1]

   generate the indices in a Cartesian system of those dimensions
  [[[1,1]],[[2,1]]]

   ensure that the indices of each coordinate is a vector (would be scalar if is a vector)
  [[[1,1]],[[2,1]]]

  ()⌷¨ index into each of those with the following:

   ⊂⊂⍺ the axes (doubly enclosed; once for to select those cells along the first and only axis, and once for ¨ to pair up each vector on the right with the entire set of axes on the left)
   2 1 2
  [[[1,1,1]],[[1,2,1]]]
[[1],[3]]

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.