On this page:
6.13.1 Axis Folds
array-axis-fold
array-axis-sum
array-axis-prod
array-axis-min
array-axis-max
array-axis-count
array-axis-and
array-axis-or
6.13.2 Whole-Array Folds
array-fold
array-all-fold
array-all-sum
array-all-prod
array-all-min
array-all-max
array-all-and
array-all-or
array-count
array-andmap
array-ormap
6.13.3 General Reductions and Expansions
array-axis-reduce
array-axis-expand
array->list-array
list-array->array

6.13 Folds, Reductions and Expansions

6.13.1 Axis Folds

procedure

(array-axis-fold arr k f)  (Array A)

  arr : (Array A)
  k : Integer
  f : (A A -> A)
(array-axis-fold arr k f init)  (Array B)
  arr : (Array A)
  k : Integer
  f : (A B -> B)
  init : B
Folds a binary function f over axis k of arr. The result has the shape of arr but with axis k removed.

The three-argument variant uses the first value of each row in axis k as init. It therefore requires axis k to have positive length.

Examples:

> (define arr (index-array #(3 4)))
> arr

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

identifier;

 either undefined or missing a type annotation

  identifier: arr51

  in: arr

> (array-axis-fold arr 0 +)

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

identifier;

 either undefined or missing a type annotation

  identifier: arr51

  in: +

> (array-axis-fold arr 1 (inst cons Index (Listof Index)) empty)

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

identifier;

 either undefined or missing a type annotation

  identifier: arr51

  in: empty

Notice that the second example returns an array of reversed lists. This is therefore a left fold; see foldl.

If you need control over the order of evaluation in axis k’s rows, see array-axis-reduce.

syntax

(array-axis-sum arr k)

(array-axis-sum arr k init)

syntax

(array-axis-prod arr k)

(array-axis-prod arr k init)
 
  arr : (Array Number)
  k : Integer
  init : Number

syntax

(array-axis-min arr k)

(array-axis-min arr k init)

syntax

(array-axis-max arr k)

(array-axis-max arr k init)
 
  arr : (Array Real)
  k : Integer
  init : Real
Some standard per-axis folds, defined in terms of array-axis-fold. The two-argument variants require axis k to have positive length.

Examples:

> (define arr (index-array #(3 4)))
> arr

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

identifier;

 either undefined or missing a type annotation

  identifier: arr52

  in: arr

> (array-axis-fold arr 1 +)

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

identifier;

 either undefined or missing a type annotation

  identifier: arr52

  in: +

> (array-axis-sum arr 1)

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

identifier;

 either undefined or missing a type annotation

  identifier: arr52

  in: 1

> (array-axis-sum arr 0 0.0)

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

identifier;

 either undefined or missing a type annotation

  identifier: arr52

  in: 0.0

procedure

(array-axis-count arr k pred?)  (Array Index)

  arr : (Array A)
  k : Integer
  pred? : (A -> Any)
Counts the elements x in rows of axis k for which (pred? x) is true.

Examples:

> (define arr (index-array #(3 3)))
> arr

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

identifier;

 either undefined or missing a type annotation

  identifier: arr53

  in: arr

> (array-axis-count arr 1 odd?)

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

identifier;

 either undefined or missing a type annotation

  identifier: arr53

  in: odd?

procedure

(array-axis-and arr k)  (Array (U A Boolean))

  arr : (Array A)
  k : Integer

procedure

(array-axis-or arr k)  (Array (U A #f))

  arr : (Array A)
  k : Integer
Apply and or or to each row in axis k of array arr. Evaluation is short-cut as with the and and or macros, which is only observable if arr is nonstrict.

In the following example, computing the second array element sets second? to #t:
> (define second? (ann #f Boolean))
> (define arr
    (parameterize ([array-strictness #f])
      (build-array #(2) (λ: ([js : Indexes])
                          (cond [(zero? (vector-ref js 0))  #f]
                                [else  (set! second? #t)
                                       #t])))))

eval:268:0: Type Checker: missing type for top-level identifier;

 either undefined or missing a type annotation

  identifier: second?54

  in: #t

  context...:

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/utils/tc-utils.rkt:123:0: report-all-errors

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/typecheck/tc-toplevel.rkt:515:0: tc-toplevel-form

   fail-to-succeed

   fail-to-succeed

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/tc-setup.rkt:39:0: tc-setup

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/typed-racket.rkt:24:4

   /Users/mflatt/build/macro/racket/collects/racket/private/more-scheme.rkt:148:2: call-with-break-parameterization

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/sandbox-lib/racket/sandbox.rkt:837:5: loop

eval:268:0: Type Checker: type mismatch;

 mutation only allowed with compatible types

  expected: Nothing

  given: True

  in: #t

  context...:

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/utils/tc-utils.rkt:123:0: report-all-errors

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/typecheck/tc-toplevel.rkt:515:0: tc-toplevel-form

   fail-to-succeed

   fail-to-succeed

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/tc-setup.rkt:39:0: tc-setup

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/typed-racket.rkt:24:4

   /Users/mflatt/build/macro/racket/collects/racket/private/more-scheme.rkt:148:2: call-with-break-parameterization

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/sandbox-lib/racket/sandbox.rkt:837:5: loop

Type Checker: Summary: 2 errors encountered

Printing arr causes (set! second? #t) to be evaluated, but applying array-axis-and does not:
> (array-axis-and arr 0)

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

identifier;

 either undefined or missing a type annotation

  identifier: arr53

  in: 0

> second?

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

identifier;

 either undefined or missing a type annotation

  identifier: second?54

  in: second?

However, if arr were strict, (set! second? #t) would be evaluated when arr was created.

6.13.2 Whole-Array Folds

procedure

(array-fold arr g)  (Array A)

  arr : (Array A)
  g : ((Array A) Index -> (Array A))
Folds g over each axis of arr, in reverse order. The arguments to g are an array (initially arr) and the current axis. It should return an array with one fewer dimension than the array given, but does not have to.

Examples:

> (define arr (index-array #(3 4)))
> arr

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

identifier;

 either undefined or missing a type annotation

  identifier: arr56

  in: arr

> (array-fold arr (λ: ([arr : (Array Integer)] [k : Index])
                    (array-axis-sum arr k)))

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

identifier;

 either undefined or missing a type annotation

  identifier: arr56

  in: k

> (apply + (array->list arr))

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

identifier;

 either undefined or missing a type annotation

  identifier: arr56

  in: arr

> (array-ref (array-fold arr (inst array->list-array (Listof* Integer)))
             #())

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

identifier;

 either undefined or missing a type annotation

  identifier: arr56

  in: #()

procedure

(array-all-fold arr f)  A

  arr : (Array A)
  f : (A A -> A)
(array-all-fold arr f init)  A
  arr : (Array A)
  f : (A A -> A)
  init : A
Folds f over every element of arr by folding f over each axis in reverse order. The two-argument variant is equivalent to
(array-ref (array-fold arr (λ: ([arr : (Array A)] [k : Index])
                             (array-axis-fold arr k f)))
           #())
and the three-argument variant is similar. The two-argument variant requires every axis to have positive length.

Examples:

> (define arr (index-array #(3 4)))
> arr

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

identifier;

 either undefined or missing a type annotation

  identifier: arr57

  in: arr

> (array-all-fold arr +)

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

identifier;

 either undefined or missing a type annotation

  identifier: arr57

  in: +

> (array-all-fold (array #[]) + 0.0)

- : Flonum [more precisely: Nonnegative-Flonum]

0.0

Because f is folded over the last axis first, it receives arr’s elements (as its first argument) in row-major order.

syntax

(array-all-sum arr)

(array-all-sum arr init)

syntax

(array-all-prod arr)

(array-all-prod arr init)
 
  arr : (Array Number)
  init : Number

syntax

(array-all-min arr)

(array-all-min arr init)

syntax

(array-all-max arr)

(array-all-max arr init)
 
  arr : (Array Real)
  init : Real
Some standard whole-array folds, defined in terms of array-all-fold. The one-argument variants require each axis in arr to have positive length.

Examples:

> (define arr (index-array #(3 4)))
> arr

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

identifier;

 either undefined or missing a type annotation

  identifier: arr58

  in: arr

> (array-all-fold arr +)

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

identifier;

 either undefined or missing a type annotation

  identifier: arr58

  in: +

> (array-all-sum arr)

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

identifier;

 either undefined or missing a type annotation

  identifier: arr58

  in: arr

> (array-all-sum arr 0.0)

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

identifier;

 either undefined or missing a type annotation

  identifier: arr58

  in: 0.0

procedure

(array-all-and arr)  (U A Boolean)

  arr : (Array A)

procedure

(array-all-or arr)  (U A #f)

  arr : (Array A)
Apply and or or to arr’s elements using short-cut evaluation in row-major order.

Examples:

> (define arr (index-array #(3 3)))
> (array-all-and (array= arr arr))

eval:286:0: Type Checker: missing type for top-level identifier;

 either undefined or missing a type annotation

  identifier: arr59

  in: arr

  context...:

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/utils/tc-utils.rkt:123:0: report-all-errors

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/typecheck/tc-toplevel.rkt:515:0: tc-toplevel-form

   fail-to-succeed

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/tc-setup.rkt:39:0: tc-setup

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/typed-racket.rkt:24:4

   /Users/mflatt/build/macro/racket/collects/racket/private/more-scheme.rkt:148:2: call-with-break-parameterization

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/sandbox-lib/racket/sandbox.rkt:837:5: loop

eval:286:0: Type Checker: missing type for top-level identifier;

 either undefined or missing a type annotation

  identifier: arr59

  in: arr

  context...:

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/utils/tc-utils.rkt:123:0: report-all-errors

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/typecheck/tc-toplevel.rkt:515:0: tc-toplevel-form

   fail-to-succeed

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/tc-setup.rkt:39:0: tc-setup

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/typed-racket.rkt:24:4

   /Users/mflatt/build/macro/racket/collects/racket/private/more-scheme.rkt:148:2: call-with-break-parameterization

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/sandbox-lib/racket/sandbox.rkt:837:5: loop

Type Checker: Summary: 2 errors encountered

> (define brr (array+ arr (array 1)))

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

identifier;

 either undefined or missing a type annotation

  identifier: arr59

  in: 1

> (array-all-and (array= arr brr))

eval:288:0: Type Checker: missing type for top-level identifier;

 either undefined or missing a type annotation

  identifier: arr59

  in: brr

  context...:

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/utils/tc-utils.rkt:123:0: report-all-errors

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/typecheck/tc-toplevel.rkt:515:0: tc-toplevel-form

   fail-to-succeed

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/tc-setup.rkt:39:0: tc-setup

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/typed-racket.rkt:24:4

   /Users/mflatt/build/macro/racket/collects/racket/private/more-scheme.rkt:148:2: call-with-break-parameterization

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/sandbox-lib/racket/sandbox.rkt:837:5: loop

eval:288:0: Type Checker: missing type for top-level identifier;

 either undefined or missing a type annotation

  identifier: brr46

  in: brr

  context...:

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/utils/tc-utils.rkt:123:0: report-all-errors

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/typecheck/tc-toplevel.rkt:515:0: tc-toplevel-form

   fail-to-succeed

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/tc-setup.rkt:39:0: tc-setup

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/typed-racket.rkt:24:4

   /Users/mflatt/build/macro/racket/collects/racket/private/more-scheme.rkt:148:2: call-with-break-parameterization

   /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/sandbox-lib/racket/sandbox.rkt:837:5: loop

Type Checker: Summary: 2 errors encountered

> (array-all-or (array= arr (array 0)))

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

identifier;

 either undefined or missing a type annotation

  identifier: arr59

  in: 0

(array-all-and arr) is defined as
and array-all-or is defined similarly, using array-axis-or.

syntax

(array-count pred? arrs ...)

 
  arrs : (Array Ts)
  pred? : (Ts ... -> Any)
When given one array arr, returns the number of elements x in arr for which (pred? x) is true. When given multiple arrays, array-count does the same with the corresponding elements from any number of arrays. If the arrays’ shapes are not the same, they are broadcast first.

Examples:

> (array-count zero? (array #[#[0 1 0 2] #[0 3 -1 4]]))

- : Integer [more precisely: Index]

3

> (array-count equal?
               (array #[#[0 1] #[2 3] #[0 1] #[2 3]])
               (array #[0 1]))

- : Integer [more precisely: Index]

4

(array-count pred? arrs ...) is like
(array-all-sum (array-map (λ (x ...) (if (pred? x ...) 1 0)) arrs ...)
               0)
but does not create intermediate (strict) arrays, and always returns an Index.

syntax

(array-andmap pred? arrs ...)

syntax

(array-ormap pred? arrs ...)

 
  arrs : (Array Ts)
  pred? : (Ts ... -> Any)
Like andmap and ormap, but for arrays. Evaluation is short-cut, in row-major order. If the arrays’ shapes are not the same, they are broadcast first.

Determining whether each row is equal to (array #[0 1]):
> (array-andmap equal?
                (array #[#[0 1] #[0 1] #[0 1] #[0 1]])
                (array #[0 1]))

- : Boolean

#t

Determining whether any row has 0 as its first element or 1 as its second:
> (array-ormap equal?
               (array #[#[0 2] #[2 3] #[1 1] #[2 3]])
               (array #[0 1]))

- : Boolean

#t

Determining whether any row is equal to (array #[0 1]):
> (array-ormap equal?
               (array->list-array (array #[#[0 2] #[2 3] #[1 1] #[2 3]]))
               (array->list-array (array #[0 1])))

- : Boolean

#f

(array-andmap pred? arrs ...) is defined as
(parameterize ([array-strictness #f])
  (array-all-and (array-map pred? arrs ...)))
and array-ormap is defined similarly, using array-all-or.

6.13.3 General Reductions and Expansions

procedure

(array-axis-reduce arr k h)  (Array B)

  arr : (Array A)
  k : Integer
  h : (Index (Integer -> A) -> B)
Like array-axis-fold, but allows evaluation control (such as short-cutting and and or) by moving the loop into h. The result has the shape of arr, but with axis k removed.

The arguments to h are the length of axis k and a procedure that retrieves elements from that axis’s rows by their indexes in axis k. It should return the elements of the resulting array.

For example, summing the squares of the rows in axis 1:
> (define arr (index-array #(3 3)))
> arr

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

identifier;

 either undefined or missing a type annotation

  identifier: arr61

  in: arr

> (array-axis-reduce
   arr 1
   (λ: ([dk : Index] [proc : (Integer -> Real)])
     (for/fold: ([s : Real 0]) ([jk  (in-range dk)])
       (+ s (sqr (proc jk))))))

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

identifier;

 either undefined or missing a type annotation

  identifier: arr61

  in: jk

> (array-axis-sum (array-map sqr arr) 1)

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

identifier;

 either undefined or missing a type annotation

  identifier: arr61

  in: 1

Transforming an axis into a list using array-axis-fold and array-axis-reduce:
> (array-map (inst reverse Index)
             (array-axis-fold arr 1
                              (inst cons Index (Listof Index))
                              empty))

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

identifier;

 either undefined or missing a type annotation

  identifier: arr61

  in: empty

> (array-axis-reduce arr 1 (inst build-list Index))

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

identifier;

 either undefined or missing a type annotation

  identifier: arr61

  in: Index

The latter is essentially the definition of array->list-array.

Every fold, including array-axis-fold, is ultimately defined using array-axis-reduce or its unsafe counterpart.

procedure

(array-axis-expand arr k dk g)  (Array B)

  arr : (Array A)
  k : Integer
  dk : Integer
  g : (A Index -> B)
Inserts a new axis number k of length dk, using g to generate values; k must be no greater than the dimension of arr, and dk must be nonnegative.

Conceptually, g is applied dk times to each element in each row of axis k, once for each nonnegative index jk < dk.

Turning vector elements into rows of a new last axis using array-axis-expand and vector-ref:
> (define arr (array #['#(a b c) '#(d e f) '#(g h i)]))
> (array-axis-expand arr 1 3 vector-ref)

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

identifier;

 either undefined or missing a type annotation

  identifier: arr62

  in: vector-ref

Creating a vandermonde-matrix:
> (array-axis-expand (list->array '(1 2 3 4)) 1 5 expt)

- : (Array Positive-Integer)

(array #[#[1 1 1 1 1] #[1 2 4 8 16] #[1 3 9 27 81] #[1 4 16 64 256]])

This function is a dual of array-axis-reduce in that it can be used to invert applications of array-axis-reduce. To do so, g should be a destructuring function that is dual to the constructor passed to array-axis-reduce. Example dual pairs are vector-ref and build-vector, and list-ref and build-list.

(Do not pass list-ref to array-axis-expand if you care about performance, though. See list-array->array for a more efficient solution.)

procedure

(array->list-array arr [k])  (Array (Listof A))

  arr : (Array A)
  k : Integer = 0
Returns an array of lists, computed as if by applying list to the elements in each row of axis k.

Examples:

> (define arr (index-array #(3 3)))
> arr

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

identifier;

 either undefined or missing a type annotation

  identifier: arr63

  in: arr

> (array->list-array arr 1)

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

identifier;

 either undefined or missing a type annotation

  identifier: arr63

  in: 1

> (array-ref (array->list-array (array->list-array arr 1) 0) #())

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

identifier;

 either undefined or missing a type annotation

  identifier: arr63

  in: #()

See mean for more useful examples, and array-axis-reduce for an example that shows how array->list-array is implemented.

procedure

(list-array->array arr [k])  (Array A)

  arr : (Array (Listof A))
  k : Integer = 0
Returns an array in which the list elements of arr comprise a new axis k. Equivalent to (array-axis-expand arr k n list-ref) where n is the length of the lists in arr, but with O(1) indexing.

Examples:

> (define arr (array->list-array (index-array #(3 3)) 1))
> arr

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

identifier;

 either undefined or missing a type annotation

  identifier: arr64

  in: arr

> (list-array->array arr 1)

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

identifier;

 either undefined or missing a type annotation

  identifier: arr64

  in: 1

For fixed k, this function and array->list-array are mutual inverses with respect to their array arguments.