On this page:
6.4.1 (Sequenceof Integer):   pick rows
6.4.2 Slice:   pick rows in a length-aware way
6.4.3 Slice-Dots:   preserve remaining axes
6.4.4 Integer:   remove an axis
6.4.5 Slice-New-Axis:   add an axis

6.4 Slicing

One common array transformation is slicing: extracting sub-arrays by picking rows from each axis independently.

Slicing is done by applying array-slice-ref or array-slice-set! to an array and a list of slice specifications corresponding to array axes. There are five types of slice specification:

Create Slice objects using :: and Slice-New-Axis objects using ::new. There is only one Slice-Dots object, namely ::....

When slicing an array with n axes, unless a list of slice specifications contains ::..., it must contain exactly n slice specifications.

The remainder of this section uses the following example array:
> (define arr
    (build-array
     #(2 3 4)
     (λ: ([js : Indexes])
       (string-append* (map number->string (vector->list js))))))
> arr

eval:44:0: Type Checker: missing type for top-level

identifier;

 either undefined or missing a type annotation

  identifier: arr19

  in: arr

6.4.1 (Sequenceof Integer): pick rows

Using a sequence of integers as a slice specification picks rows from the corresponding axis. For example, we might use lists of integers to pick every row from every axis:
> (array-slice-ref arr (list '(0 1) '(0 1 2) '(0 1 2 3)))

eval:45:0: Type Checker: missing type for top-level

identifier;

 either undefined or missing a type annotation

  identifier: arr19

  in: 3

This simply copies the array.

More usefully, we can use sequences to swap rows on the same axis:
> (array-slice-ref arr (list '(1 0) '(0 1 2) '(0 1 2 3)))

eval:46:0: Type Checker: missing type for top-level

identifier;

 either undefined or missing a type annotation

  identifier: arr19

  in: 3

We can also remove rows:
> (array-slice-ref arr (list '(0 1) '(0 2) '(0 2)))

eval:47:0: Type Checker: missing type for top-level

identifier;

 either undefined or missing a type annotation

  identifier: arr19

  in: 2

> (array-slice-ref arr (list '(0 1) '(0 1 2) '()))

eval:48:0: Type Checker: missing type for top-level

identifier;

 either undefined or missing a type annotation

  identifier: arr19

  in: ()

Or duplicate rows:
> (array-slice-ref arr (list '(0 1) '(0 1 2) '(0 0 1 2 2 3)))

eval:49:0: Type Checker: missing type for top-level

identifier;

 either undefined or missing a type annotation

  identifier: arr19

  in: 3

However, a sequence slice specification cannot alter the number of axes.

Using sequence constructors like in-range, we can pick every even-indexed row in an axis:
> (array-slice-ref arr (list '(1 0) '(0 1 2) (in-range 0 4 2)))

eval:50:0: Type Checker: missing type for top-level

identifier;

 either undefined or missing a type annotation

  identifier: arr19

  in: 2

We could also use in-range to pick every row instead of enumerating their indexes in a list, but that would require another kind of tedium:
> (define ds (array-shape arr))

eval:51:0: Type Checker: missing type for top-level

identifier;

 either undefined or missing a type annotation

  identifier: arr19

  in: arr

> (array-slice-ref arr (list (in-range (vector-ref ds 0))
                             (in-range (vector-ref ds 1))
                             (in-range (vector-ref ds 2))))

eval:52:0: ds20: unbound identifier;

 also, no #%top syntax transformer is bound

  in: ds20

The situation calls for an in-range-like slice specification that is aware of the lengths of the axes it is applied to.

6.4.2 Slice: pick rows in a length-aware way

As a slice specification, a Slice object acts like the sequence object returned by in-range, but either start or end may be #f.

If start is #f, it is interpreted as the first valid axis index in the direction of step. If end is #f, it is interpreted as the last valid axis index in the direction of step.

Possibly the most common slice is (::), equivalent to (:: #f #f 1). With a positive step = 1, start is interpreted as 0 and end as the length of the axis. Thus, (::) picks all rows from any axis:
> (array-slice-ref arr (list (::) (::) (::)))

eval:53:0: Type Checker: missing type for top-level

identifier;

 either undefined or missing a type annotation

  identifier: arr19

  in: ::

The slice (:: #f #f -1) reverses an axis:
> (array-slice-ref arr (list (::) (::) (:: #f #f -1)))

eval:54:0: Type Checker: missing type for top-level

identifier;

 either undefined or missing a type annotation

  identifier: arr19

  in: -1

The slice (:: 2 #f 1) picks every row starting from index 2:
> (array-slice-ref arr (list (::) (::) (:: 2 #f 1)))

eval:55:0: Type Checker: missing type for top-level

identifier;

 either undefined or missing a type annotation

  identifier: arr19

  in: 1

The slice (:: 1 #f 2) picks every odd-indexed row:
> (array-slice-ref arr (list (::) (::) (:: 1 #f 2)))

eval:56:0: Type Checker: missing type for top-level

identifier;

 either undefined or missing a type annotation

  identifier: arr19

  in: 2

Notice that every example starts with two (::). In fact, slicing only one axis is so common that there is a slice specification object that represents any number of (::).

6.4.3 Slice-Dots: preserve remaining axes

As a slice specification, a Slice-Dots object represents any number of leftover, adjacent axes, and preserves them all.

For example, picking every odd-indexed row of the last axis can be done by
> (array-slice-ref arr (list ::... (:: 1 #f 2)))

eval:57:0: Type Checker: missing type for top-level

identifier;

 either undefined or missing a type annotation

  identifier: arr19

  in: 2

For arr specifically, ::... represents two (::).

Slicing only the first axis while preserving the rest can be done by
> (array-slice-ref arr (list '(0) ::...))

eval:58:0: Type Checker: missing type for top-level

identifier;

 either undefined or missing a type annotation

  identifier: arr19

  in: ::...

If more than one ::... appears in the list, only the first is expanded:
> (array-slice-ref arr (list ::... '(1) ::...))

eval:59:0: Type Checker: missing type for top-level

identifier;

 either undefined or missing a type annotation

  identifier: arr19

  in: ::...

> (array-slice-ref arr (list ::... '(1)))

eval:60:0: Type Checker: missing type for top-level

identifier;

 either undefined or missing a type annotation

  identifier: arr19

  in: 1

If there are no leftover axes, ::... does nothing when placed in any position:
> (array-slice-ref arr (list ::... '(1) '(1) '(1)))

eval:61:0: Type Checker: missing type for top-level

identifier;

 either undefined or missing a type annotation

  identifier: arr19

  in: 1

> (array-slice-ref arr (list '(1) ::... '(1) '(1)))

eval:62:0: Type Checker: missing type for top-level

identifier;

 either undefined or missing a type annotation

  identifier: arr19

  in: 1

> (array-slice-ref arr (list '(1) '(1) ::... '(1)))

eval:63:0: Type Checker: missing type for top-level

identifier;

 either undefined or missing a type annotation

  identifier: arr19

  in: 1

> (array-slice-ref arr (list '(1) '(1) '(1) ::...))

eval:64:0: Type Checker: missing type for top-level

identifier;

 either undefined or missing a type annotation

  identifier: arr19

  in: ::...

6.4.4 Integer: remove an axis

All of the slice specifications so far preserve the dimensions of the array. Removing an axis can be done by using an integer as a slice specification.

This example removes the first axis by collapsing it to its first row:
> (array-slice-ref arr (list 0 ::...))

eval:65:0: Type Checker: missing type for top-level

identifier;

 either undefined or missing a type annotation

  identifier: arr19

  in: ::...

Removing the second axis by collapsing it to the row with index 1:
> (array-slice-ref arr (list (::) 1 ::...))

eval:66:0: Type Checker: missing type for top-level

identifier;

 either undefined or missing a type annotation

  identifier: arr19

  in: ::...

Removing the second-to-last axis (which for arr is the same as the second):
> (array-slice-ref arr (list ::... 1 (::)))

eval:67:0: Type Checker: missing type for top-level

identifier;

 either undefined or missing a type annotation

  identifier: arr19

  in: ::

All of these examples can be done using array-axis-ref. However, removing an axis relative to the dimension of the array (e.g. the second-to-last axis) is easier to do using array-slice-ref, and it is sometimes convenient to combine axis removal with other slice operations.

6.4.5 Slice-New-Axis: add an axis

As a slice specification, (::new dk) inserts dk into the resulting array’s shape, in the corresponding axis position. The new axis has length dk, which must be nonnegative.

For example, we might conceptually wrap another #[] around an array’s data:
> (array-slice-ref arr (list (::new) ::...))

eval:68:0: Type Checker: missing type for top-level

identifier;

 either undefined or missing a type annotation

  identifier: arr19

  in: ::...

Or duplicate the array twice, within two new outer rows:
> (array-slice-ref arr (list (::new 2) ::...))

eval:69:0: Type Checker: missing type for top-level

identifier;

 either undefined or missing a type annotation

  identifier: arr19

  in: ::...

Of course, dk = 0 is a valid new axis length, but is usually not very useful:
> (array-slice-ref arr (list (::) (::new 0) ::...))

eval:70:0: Type Checker: missing type for top-level

identifier;

 either undefined or missing a type annotation

  identifier: arr19

  in: ::...

Inserting axes can also be done using array-axis-insert.