W3cubDocs

/Julia 0.6

Multi-dimensional Arrays

Julia, like most technical computing languages, provides a first-class array implementation. Most technical computing languages pay a lot of attention to their array implementation at the expense of other containers. Julia does not treat arrays in any special way. The array library is implemented almost completely in Julia itself, and derives its performance from the compiler, just like any other code written in Julia. As such, it's also possible to define custom array types by inheriting from AbstractArray. See the manual section on the AbstractArray interface for more details on implementing a custom array type.

An array is a collection of objects stored in a multi-dimensional grid. In the most general case, an array may contain objects of type Any. For most computational purposes, arrays should contain objects of a more specific type, such as Float64 or Int32.

In general, unlike many other technical computing languages, Julia does not expect programs to be written in a vectorized style for performance. Julia's compiler uses type inference and generates optimized code for scalar array indexing, allowing programs to be written in a style that is convenient and readable, without sacrificing performance, and using less memory at times.

In Julia, all arguments to functions are passed by reference. Some technical computing languages pass arrays by value, and this is convenient in many cases. In Julia, modifications made to input arrays within a function will be visible in the parent function. The entire Julia array library ensures that inputs are not modified by library functions. User code, if it needs to exhibit similar behavior, should take care to create a copy of inputs that it may modify.

Arrays

Basic Functions

Function Description
eltype(A) the type of the elements contained in A
length(A) the number of elements in A
ndims(A) the number of dimensions of A
size(A) a tuple containing the dimensions of A
size(A,n) the size of A along dimension n
indices(A) a tuple containing the valid indices of A
indices(A,n) a range expressing the valid indices along dimension n
eachindex(A) an efficient iterator for visiting each position in A
stride(A,k) the stride (linear index distance between adjacent elements) along dimension k
strides(A) a tuple of the strides in each dimension

Construction and Initialization

Many functions for constructing and initializing arrays are provided. In the following list of such functions, calls with a dims... argument can either take a single tuple of dimension sizes or a series of dimension sizes passed as a variable number of arguments. Most of these functions also accept a first input T, which is the element type of the array. If the type T is omitted it will default to Float64.

Function Description
Array{T}(dims...) an uninitialized dense Array
zeros(T, dims...) an Array of all zeros
zeros(A) an array of all zeros with the same type, element type and shape as A
ones(T, dims...) an Array of all ones
ones(A) an array of all ones with the same type, element type and shape as A
trues(dims...) a BitArray with all values true
trues(A) a BitArray with all values true and the same shape as A
falses(dims...) a BitArray with all values false
falses(A) a BitArray with all values false and the same shape as A
reshape(A, dims...) an array containing the same data as A, but with different dimensions
copy(A) copy A
deepcopy(A) copy A, recursively copying its elements
similar(A, T, dims...) an uninitialized array of the same type as A (dense, sparse, etc.), but with the specified element type and dimensions. The second and third arguments are both optional, defaulting to the element type and dimensions of A if omitted.
reinterpret(T, A) an array with the same binary data as A, but with element type T
rand(T, dims...) an Array with random, iid [1] and uniformly distributed values in the half-open interval $[0, 1)$
randn(T, dims...) an Array with random, iid and standard normally distributed values
eye(T, n) n-by-n identity matrix
eye(T, m, n) m-by-n identity matrix
linspace(start, stop, n) range of n linearly spaced elements from start to stop
fill!(A, x) fill the array A with the value x
fill(x, dims...) an Array filled with the value x
[1]

iid, independently and identically distributed.

The syntax [A, B, C, ...] constructs a 1-d array (vector) of its arguments. If all arguments have a common promotion type then they get converted to that type using convert().

Concatenation

Arrays can be constructed and also concatenated using the following functions:

Function Description
cat(k, A...) concatenate input n-d arrays along the dimension k
vcat(A...) shorthand for cat(1, A...)
hcat(A...) shorthand for cat(2, A...)

Scalar values passed to these functions are treated as 1-element arrays.

The concatenation functions are used so often that they have special syntax:

Expression Calls
[A; B; C; ...] vcat()
[A B C ...] hcat()
[A B; C D; ...] hvcat()

hvcat() concatenates in both dimension 1 (with semicolons) and dimension 2 (with spaces).

Typed array initializers

An array with a specific element type can be constructed using the syntax T[A, B, C, ...]. This will construct a 1-d array with element type T, initialized to contain elements A, B, C, etc. For example Any[x, y, z] constructs a heterogeneous array that can contain any values.

Concatenation syntax can similarly be prefixed with a type to specify the element type of the result.

julia> [[1 2] [3 4]]
1×4 Array{Int64,2}:
 1  2  3  4

julia> Int8[[1 2] [3 4]]
1×4 Array{Int8,2}:
 1  2  3  4

Comprehensions

Comprehensions provide a general and powerful way to construct arrays. Comprehension syntax is similar to set construction notation in mathematics:

A = [ F(x,y,...) for x=rx, y=ry, ... ]

The meaning of this form is that F(x,y,...) is evaluated with the variables x, y, etc. taking on each value in their given list of values. Values can be specified as any iterable object, but will commonly be ranges like 1:n or 2:(n-1), or explicit arrays of values like [1.2, 3.4, 5.7]. The result is an N-d dense array with dimensions that are the concatenation of the dimensions of the variable ranges rx, ry, etc. and each F(x,y,...) evaluation returns a scalar.

The following example computes a weighted average of the current element and its left and right neighbor along a 1-d grid. :

julia> x = rand(8)
8-element Array{Float64,1}:
 0.843025
 0.869052
 0.365105
 0.699456
 0.977653
 0.994953
 0.41084
 0.809411

julia> [ 0.25*x[i-1] + 0.5*x[i] + 0.25*x[i+1] for i=2:length(x)-1 ]
6-element Array{Float64,1}:
 0.736559
 0.57468
 0.685417
 0.912429
 0.8446
 0.656511

The resulting array type depends on the types of the computed elements. In order to control the type explicitly, a type can be prepended to the comprehension. For example, we could have requested the result in single precision by writing:

Float32[ 0.25*x[i-1] + 0.5*x[i] + 0.25*x[i+1] for i=2:length(x)-1 ]

Generator Expressions

Comprehensions can also be written without the enclosing square brackets, producing an object known as a generator. This object can be iterated to produce values on demand, instead of allocating an array and storing them in advance (see Iteration). For example, the following expression sums a series without allocating memory:

julia> sum(1/n^2 for n=1:1000)
1.6439345666815615

When writing a generator expression with multiple dimensions inside an argument list, parentheses are needed to separate the generator from subsequent arguments:

julia> map(tuple, 1/(i+j) for i=1:2, j=1:2, [1:4;])
ERROR: syntax: invalid iteration specification

All comma-separated expressions after for are interpreted as ranges. Adding parentheses lets us add a third argument to map:

julia> map(tuple, (1/(i+j) for i=1:2, j=1:2), [1 3; 2 4])
2×2 Array{Tuple{Float64,Int64},2}:
 (0.5, 1)       (0.333333, 3)
 (0.333333, 2)  (0.25, 4)

Ranges in generators and comprehensions can depend on previous ranges by writing multiple for keywords:

julia> [(i,j) for i=1:3 for j=1:i]
6-element Array{Tuple{Int64,Int64},1}:
 (1, 1)
 (2, 1)
 (2, 2)
 (3, 1)
 (3, 2)
 (3, 3)

In such cases, the result is always 1-d.

Generated values can be filtered using the if keyword:

julia> [(i,j) for i=1:3 for j=1:i if i+j == 4]
2-element Array{Tuple{Int64,Int64},1}:
 (2, 2)
 (3, 1)

Indexing

The general syntax for indexing into an n-dimensional array A is:

X = A[I_1, I_2, ..., I_n]

where each I_k may be a scalar integer, an array of integers, or any other supported index. This includes Colon (:) to select all indices within the entire dimension, ranges of the form a:c or a:b:c to select contiguous or strided subsections, and arrays of booleans to select elements at their true indices.

If all the indices are scalars, then the result X is a single element from the array A. Otherwise, X is an array with the same number of dimensions as the sum of the dimensionalities of all the indices.

If all indices are vectors, for example, then the shape of X would be (length(I_1), length(I_2), ..., length(I_n)), with location (i_1, i_2, ..., i_n) of X containing the value A[I_1[i_1], I_2[i_2], ..., I_n[i_n]]. If I_1 is changed to a two-dimensional matrix, then X becomes an n+1-dimensional array of shape (size(I_1, 1), size(I_1, 2), length(I_2), ..., length(I_n)). The matrix adds a dimension. The location (i_1, i_2, i_3, ..., i_{n+1}) contains the value at A[I_1[i_1, i_2], I_2[i_3], ..., I_n[i_{n+1}]]. All dimensions indexed with scalars are dropped. For example, the result of A[2, I, 3] is an array with size size(I). Its ith element is populated by A[2, I[i], 3].

As a special part of this syntax, the end keyword may be used to represent the last index of each dimension within the indexing brackets, as determined by the size of the innermost array being indexed. Indexing syntax without the end keyword is equivalent to a call to getindex:

X = getindex(A, I_1, I_2, ..., I_n)

Example:

julia> x = reshape(1:16, 4, 4)
4×4 Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}}:
 1  5   9  13
 2  6  10  14
 3  7  11  15
 4  8  12  16

julia> x[2:3, 2:end-1]
2×2 Array{Int64,2}:
 6  10
 7  11

julia> x[1, [2 3; 4 1]]
2×2 Array{Int64,2}:
  5  9
 13  1

Empty ranges of the form n:n-1 are sometimes used to indicate the inter-index location between n-1 and n. For example, the searchsorted() function uses this convention to indicate the insertion point of a value not found in a sorted array:

julia> a = [1,2,5,6,7];

julia> searchsorted(a, 3)
3:2

Assignment

The general syntax for assigning values in an n-dimensional array A is:

A[I_1, I_2, ..., I_n] = X

where each I_k may be a scalar integer, an array of integers, or any other supported index. This includes Colon (:) to select all indices within the entire dimension, ranges of the form a:c or a:b:c to select contiguous or strided subsections, and arrays of booleans to select elements at their true indices.

If X is an array, it must have the same number of elements as the product of the lengths of the indices: prod(length(I_1), length(I_2), ..., length(I_n)). The value in location I_1[i_1], I_2[i_2], ..., I_n[i_n] of A is overwritten with the value X[i_1, i_2, ..., i_n]. If X is not an array, its value is written to all referenced locations of A.

Just as in Indexing, the end keyword may be used to represent the last index of each dimension within the indexing brackets, as determined by the size of the array being assigned into. Indexed assignment syntax without the end keyword is equivalent to a call to setindex!():

setindex!(A, X, I_1, I_2, ..., I_n)

Example:

julia> x = collect(reshape(1:9, 3, 3))
3×3 Array{Int64,2}:
 1  4  7
 2  5  8
 3  6  9

julia> x[1:2, 2:3] = -1
-1

julia> x
3×3 Array{Int64,2}:
 1  -1  -1
 2  -1  -1
 3   6   9

Supported index types

In the expression A[I_1, I_2, ..., I_n], each I_k may be a scalar index, an array of scalar indices, or an object that represents an array of scalar indices and can be converted to such by to_indices:

  1. A scalar index. By default this includes:

    • Non-boolean integers

    • CartesianIndex{N}s, which behave like an N-tuple of integers spanning multiple dimensions (see below for more details)

  2. An array of scalar indices. This includes:

    • Vectors and multidimensional arrays of integers

    • Empty arrays like [], which select no elements

    • Ranges of the form a:c or a:b:c, which select contiguous or strided subsections from a to c (inclusive)

    • Any custom array of scalar indices that is a subtype of AbstractArray

    • Arrays of CartesianIndex{N} (see below for more details)

  3. An object that represents an array of scalar indices and can be converted to such by to_indices. By default this includes:

    • Colon() (:), which represents all indices within an entire dimension or across the entire array

    • Arrays of booleans, which select elements at their true indices (see below for more details)

Cartesian indices

The special CartesianIndex{N} object represents a scalar index that behaves like an N-tuple of integers spanning multiple dimensions. For example:

julia> A = reshape(1:32, 4, 4, 2);

julia> A[3, 2, 1]
7

julia> A[CartesianIndex(3, 2, 1)] == A[3, 2, 1] == 7
true

Considered alone, this may seem relatively trivial; CartesianIndex simply gathers multiple integers together into one object that represents a single multidimensional index. When combined with other indexing forms and iterators that yield CartesianIndexes, however, this can lead directly to very elegant and efficient code. See Iteration below, and for some more advanced examples, see this blog post on multidimensional algorithms and iteration.

Arrays of CartesianIndex{N} are also supported. They represent a collection of scalar indices that each span N dimensions, enabling a form of indexing that is sometimes referred to as pointwise indexing. For example, it enables accessing the diagonal elements from the first "page" of A from above:

julia> page = A[:,:,1]
4×4 Array{Int64,2}:
 1  5   9  13
 2  6  10  14
 3  7  11  15
 4  8  12  16

julia> page[[CartesianIndex(1,1),
             CartesianIndex(2,2),
             CartesianIndex(3,3),
             CartesianIndex(4,4)]]
4-element Array{Int64,1}:
  1
  6
 11
 16

This can be expressed much more simply with dot broadcasting and by combining it with a normal integer index (instead of extracting the first page from A as a separate step). It can even be combined with a : to extract both diagonals from the two pages at the same time:

julia> A[CartesianIndex.(indices(A, 1), indices(A, 2)), 1]
4-element Array{Int64,1}:
  1
  6
 11
 16

julia> A[CartesianIndex.(indices(A, 1), indices(A, 2)), :]
4×2 Array{Int64,2}:
  1  17
  6  22
 11  27
 16  32
Warning

CartesianIndex and arrays of CartesianIndex are not compatible with the end keyword to represent the last index of a dimension. Do not use end in indexing expressions that may contain either CartesianIndex or arrays thereof.

Logical indexing

Often referred to as logical indexing or indexing with a logical mask, indexing by a boolean array selects elements at the indices where its values are true. Indexing by a boolean vector B is effectively the same as indexing by the vector of integers that is returned by find(B). Similarly, indexing by a N-dimensional boolean array is effectively the same as indexing by the vector of CartesianIndex{N}s where its values are true. A logical index must be a vector of the same length as the dimension it indexes into, or it must be the only index provided and match the size and dimensionality of the array it indexes into. It is generally more efficient to use boolean arrays as indices directly instead of first calling find(calling 32"> calling find(calling 32"> calling Cartiselytesues why is effect(fectively t(k, A.ing an integer to a Ptre as ieby abimilar to(i xing by the vector of integers that is returne>n

Em2bc5db2b1he expressIEEm2bc5db2b1he expressIEEm2bc5db2b1he expressIEEm2bc5db2b1he expressIEEm2bc5db2b1he expressI, indexingad of c5db2b1 9 13 1

Emptynde>mT lhffectces tha(ficing performance, and usssignme="#">p4.y ttieltiple di5":../stg multiple osional algorithmhe araa> Arficing0 multiple bb25c25>

The ay, i(i xiformance, and 5>

The ay, i(i xiformance, and 5>

The ay, i(i xiformance, a> A = raccei xiformanPraccei 5c25>

The ay, i(i xiformance, and 5>

The ay, i(i xiformance, and 5>

The ay, i(i xiformance, a> A = raccei xiformanPraccei 5c25>

The ay, i(i xiformance, and 5>

The ay, i(i xiformance, and 5>

The ay, i(i], ..., I_n[i_ne ay, i(i xiformance, a&gt(i x*T2artesianIne, and 5>

The ay, i(i xiformanc ay, i(i xiformance, anges of theHay/../../stdit _ensional grid.e> > The ntrue

The ntr general>julia&gcodtlsoa td> is anas iebyo*dimension)ri as ieb(bimilar to(i/p>
jumde>cglobal()[i_1, i_2], I_2he ntreleaseg.nme="#ber of eialues in te="../../stdlii}ne>Fay witing by tUi/tr>owever, t/pre>

Emgcosyntbyo*o custom arrao(yntax fortRcode>find(cn form Fay wit="#"> owever, t/pre>

Emgcosyntbyo*o custom arrao(yntax fortRcode>find(c(i+j)7o(yntrao(rrayndelvional booluses this rao(yntaxith the Fay ge"ndexed wid tori}ils)