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

- : (Array String)

(array

 #[#[#["000" "001" "002" "003"]

     #["010" "011" "012" "013"]

     #["020" "021" "022" "023"]]

   #[#["100" "101" "102" "103"]

     #["110" "111" "112" "113"]

     #["120" "121" "122" "123"]]])

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

- : (Array String)

(array

 #[#[#["000" "001" "002" "003"]

     #["010" "011" "012" "013"]

     #["020" "021" "022" "023"]]

   #[#["100" "101" "102" "103"]

     #["110" "111" "112" "113"]

     #["120" "121" "122" "123"]]])

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

- : (Array String)

(array

 #[#[#["100" "101" "102" "103"]

     #["110" "111" "112" "113"]

     #["120" "121" "122" "123"]]

   #[#["000" "001" "002" "003"]

     #["010" "011" "012" "013"]

     #["020" "021" "022" "023"]]])

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

- : (Array String)

(array #[#[#["000" "002"] #["020" "022"]] #[#["100" "102"] #["120" "122"]]])

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

- : (Array String)

(array #[#[#[] #[] #[]] #[#[] #[] #[]]])

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

- : (Array String)

(array

 #[#[#["000" "000" "001" "002" "002" "003"]

     #["010" "010" "011" "012" "012" "013"]

     #["020" "020" "021" "022" "022" "023"]]

   #[#["100" "100" "101" "102" "102" "103"]

     #["110" "110" "111" "112" "112" "113"]

     #["120" "120" "121" "122" "122" "123"]]])

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

- : (Array String)

(array

 #[#[#["100" "102"]

     #["110" "112"]

     #["120" "122"]]

   #[#["000" "002"]

     #["010" "012"]

     #["020" "022"]]])

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))
> (array-slice-ref arr (list (in-range (vector-ref ds 0))
                             (in-range (vector-ref ds 1))
                             (in-range (vector-ref ds 2))))

- : (Array String)

(array

 #[#[#["000" "001" "002" "003"]

     #["010" "011" "012" "013"]

     #["020" "021" "022" "023"]]

   #[#["100" "101" "102" "103"]

     #["110" "111" "112" "113"]

     #["120" "121" "122" "123"]]])

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 (::) (::) (::)))

- : (Array String)

(array

 #[#[#["000" "001" "002" "003"]

     #["010" "011" "012" "013"]

     #["020" "021" "022" "023"]]

   #[#["100" "101" "102" "103"]

     #["110" "111" "112" "113"]

     #["120" "121" "122" "123"]]])

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

- : (Array String)

(array

 #[#[#["003" "002" "001" "000"]

     #["013" "012" "011" "010"]

     #["023" "022" "021" "020"]]

   #[#["103" "102" "101" "100"]

     #["113" "112" "111" "110"]

     #["123" "122" "121" "120"]]])

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

- : (Array String)

(array

 #[#[#["002" "003"]

     #["012" "013"]

     #["022" "023"]]

   #[#["102" "103"]

     #["112" "113"]

     #["122" "123"]]])

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

- : (Array String)

(array

 #[#[#["001" "003"]

     #["011" "013"]

     #["021" "023"]]

   #[#["101" "103"]

     #["111" "113"]

     #["121" "123"]]])

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

- : (Array String)

(array

 #[#[#["001" "003"]

     #["011" "013"]

     #["021" "023"]]

   #[#["101" "103"]

     #["111" "113"]

     #["121" "123"]]])

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

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

- : (Array String)

(array

 #[#[#["000" "001" "002" "003"]

     #["010" "011" "012" "013"]

     #["020" "021" "022" "023"]]])

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

- : (Array String)

(array #[#[#["001"] #["011"] #["021"]] #[#["101"] #["111"] #["121"]]])

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

- : (Array String)

(array #[#[#["001"] #["011"] #["021"]] #[#["101"] #["111"] #["121"]]])

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

- : (Array String)

(array #[#[#["111"]]])

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

- : (Array String)

(array #[#[#["111"]]])

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

- : (Array String)

(array #[#[#["111"]]])

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

- : (Array String)

(array #[#[#["111"]]])

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 ::...))

- : (Array String)

(array

 #[#["000" "001" "002" "003"]

   #["010" "011" "012" "013"]

   #["020" "021" "022" "023"]])

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

- : (Array String)

(array #[#["010" "011" "012" "013"] #["110" "111" "112" "113"]])

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

- : (Array String)

(array #[#["010" "011" "012" "013"] #["110" "111" "112" "113"]])

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) ::...))

- : (Array String)

(array

 #[#[#[#["000" "001" "002" "003"]

       #["010" "011" "012" "013"]

       #["020" "021" "022" "023"]]

     #[#["100" "101" "102" "103"]

       #["110" "111" "112" "113"]

       #["120" "121" "122" "123"]]]])

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

- : (Array String)

(array

 #[#[#[#["000" "001" "002" "003"]

       #["010" "011" "012" "013"]

       #["020" "021" "022" "023"]]

     #[#["100" "101" "102" "103"]

       #["110" "111" "112" "113"]

       #["120" "121" "122" "123"]]]

   #[#[#["000" "001" "002" "003"]

       #["010" "011" "012" "013"]

       #["020" "021" "022" "023"]]

     #[#["100" "101" "102" "103"]

       #["110" "111" "112" "113"]

       #["120" "121" "122" "123"]]]])

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

- : (Array String)

(array #[#[] #[]])

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