2.2. Multi-dimensional Arrays#
So far, we’ve only seen one-dimensional arrays, or vectors. But arrays can have multiple dimensions. A 2D array is a natural way to represent a matrix.
To create a matrix manually, you can use a syntax similar to vectors. Use spaces to separate elements within a row (columns) and semicolons to separate the rows themselves.
# Create a 2x3 matrix. Spaces separate columns, and a semicolon starts a new row.
A = [1 2 3; -4 -5 -6]
2×3 Matrix{Int64}:
1 2 3
-4 -5 -6
# Let's check the type of our new variable A.
typeof(A)
Matrix{Int64} (alias for Array{Int64, 2})
Notice the type: Matrix{Int64}
. This is just an alias for Array{Int64, 2}
, which tells us it’s a 2-dimensional array of 64-bit integers.
To access elements in a multi-dimensional array, you provide each index separated by a comma, typically as [row, column]
.
# Access the element in the 2nd row, 3rd column.
A[2, 3]
-6
2.2.1. Querying Array Dimensions#
You can inspect the dimensions of multi-dimensional arrays using familiar functions. For instance, length
returns the total number of elements in the array (i.e., rows × columns for a matrix).
# Get the total number of elements in the matrix (2 * 3 = 6).
length(A)
6
The size
function is more specific. You can use it to get the size of the array along a particular dimension.
# Get the size of the first dimension (number of rows).
size(A, 1)
2
# Get the size of the second dimension (number of columns).
size(A, 2)
3
2.2.2. Iterating Over Matrices#
We can use the size
function to construct loops that traverse every element in a matrix. A common pattern for this is a nested for-loop.
sumA = 0
for i = 1:size(A, 1)
for j = 1:size(A, 2)
sumA += A[i, j]
end
end
println("Sum of the elements in A = ", sumA)
Sum of the elements in A = -9
For each iteration of the outer loop (controlled by i
), the inner loop (controlled by j
) completes its entire cycle. For our 2x3 matrix A
, the loop produces index pairs (i, j)
in the following order:
(1,1)
, (1,2)
, (1,3)
, then (2,1)
, (2,2)
, (2,3)
.
2.2.2.1. Compact Nested Loops#
Julia provides a more compact syntax for nested for-loops by placing the loop variables on the same line, separated by a comma. This is functionally identical to the code above.
sumA = 0
# This compact syntax is equivalent to the nested loop above.
for i = 1:size(A, 1), j = 1:size(A, 2)
sumA += A[i, j]
end
println("Sum of the elements in A = ", sumA)
Sum of the elements in A = -9
2.2.2.2. Iterating Over Elements Directly#
If you don’t need the indices i
and j
and just want to access each element, you can use the simpler in
syntax, just like with 1D arrays.
sumAsquared = 0
# Here, 'a' will take on the value of each element in A, one by one.
for a in A
sumAsquared += a^2
end
print("Sum of the squares of the elements in A = ", sumAsquared)
Sum of the squares of the elements in A = 91
2.2.3. Creating Multi-dimensional Arrays#
The built-in functions for creating arrays can be extended to any number of dimensions by providing a tuple of the desired dimensions instead of a single length. 📏
Function |
Description |
---|---|
|
An array of size |
|
An array of size |
|
A boolean array of size |
|
A boolean array of size |
|
An array of size |
Here, dims
is a tuple of integers specifying the size of each dimension, like (rows, columns)
. For zeros
and ones
, the type T
is optional and defaults to Float64
.
# Create a 5x3 matrix of Float64s, initialized to 1.0.
# Note: If the type is omitted, it defaults to Float64.
C = ones(5, 3)
5×3 Matrix{Float64}:
1.0 1.0 1.0
1.0 1.0 1.0
1.0 1.0 1.0
1.0 1.0 1.0
1.0 1.0 1.0
2.2.3.1. Vectors vs. Matrices: An Important Distinction#
It’s crucial to understand that Julia distinguishes between a 1D array (Vector
) and a 2D array (Matrix
) that happens to have only one column or one row. This is different from other languages like MATLAB, which treats all arrays as 2D.
# A 5-element, 1-dimensional array (a true Vector).
ones(5)
5-element Vector{Float64}:
1.0
1.0
1.0
1.0
1.0
# A 5x1, 2-dimensional array (a Matrix), also known as a column vector.
ones(5, 1)
5×1 Matrix{Float64}:
1.0
1.0
1.0
1.0
1.0
# A 1x5, 2-dimensional array (a Matrix), also known as a row vector.
ones(1, 5)
1×5 Matrix{Float64}:
1.0 1.0 1.0 1.0 1.0
2.2.4. Concatenating Arrays#
You can build new matrices by concatenating or “stacking” existing arrays. The square bracket syntax []
is used for this, just as with creation.
Semicolons (
;
) stack arrays vertically.Spaces concatenate arrays horizontally.
# Vertical concatenation: Arrays must have the same number of columns.
D = [A; ones(1, 3)]
# Horizontal concatenation: Arrays must have the same number of rows.
E = [zeros(2) A]
# General concatenation: Dimensions of blocks must be consistent.
F = [A ones(2, 2); zeros(1, 5)]
3×5 Matrix{Float64}:
1.0 2.0 3.0 1.0 1.0
-4.0 -5.0 -6.0 1.0 1.0
0.0 0.0 0.0 0.0 0.0
When you include ranges in horizontal concatenation, Julia automatically expands them into column vectors.
# The ranges 1:5 and 101:105 are each treated as a 5x1 column vector here.
G = [1:5 ones(Int64, 5) 101:105]
5×3 Matrix{Int64}:
1 1 101
2 1 102
3 1 103
4 1 104
5 1 105
2.2.5. Element-wise Operations and Slicing#
The dot-syntax for element-wise operations and the colon (:
) for slicing work just as powerfully on multi-dimensional arrays.
# The dot-syntax applies operations element-by-element.
B = A.^2 .- 3A
2×3 Matrix{Int64}:
-2 -2 0
28 40 54
# The @. macro is a convenient shortcut to apply the dot to every operation in an expression.
B = @. A^2 - 3A
2×3 Matrix{Int64}:
-2 -2 0
28 40 54
2.2.5.1. Slicing Matrices#
Slicing works as before, but now you can specify ranges for each dimension to extract sub-matrices, rows, or columns.
# Select all columns (:) from the first row. The result is a 1D Vector.
A[1, :]
3-element Vector{Int64}:
1
2
3
# Select all rows (:) from the first column.
A[:, 1]
2-element Vector{Int64}:
1
-4
# Select all rows from columns 2 through 3. The result is a new 2x2 Matrix.
A[:, 2:3]
2×2 Matrix{Int64}:
2 3
-5 -6
2.2.5.2. Modifying with Slices#
You can also use slicing on the left side of an assignment to modify parts of an array in-place.
# The . in `.=` is important! It broadcasts the assignment, setting every element
# in the selected columns (1 and 3) to 0.
A[:, [1, 3]] .= 0
A
2×3 Matrix{Int64}:
0 2 0
0 -5 0
# Assign a new matrix slice to another. The dimensions on both sides must match.
# Here, we set columns 2 & 3 to be twice the values of columns 1 & 2.
A[:, 2:3] = 2 * A[:, 1:2]
A
2×3 Matrix{Int64}:
0 0 4
0 0 -10