Introducing Julia/Arrays and tuples

Storage: Arrays and Tuples
In Julia, groups of related items are usually stored in arrays, tuples, or dictionaries. Arrays can be used for storing vectors and matrices. This section concentrates on arrays and tuples; for more on dictionaries, see Dictionaries and Sets.

Arrays
An array is an ordered collection of elements. It's often indicated with square brackets and comma-separated items. You can create arrays that are full or empty, and arrays that hold values of different types or restricted to values of a specific type.

In Julia, arrays are used for lists, vectors, tables, and matrices.

A one-dimensional array acts as a vector or list. A 2-D array can be used as a table or matrix. And 3-D and more-D arrays are similarly thought of as multi-dimensional matrices.

Creating simple arrays
Here's how to create a simple one-dimensional array:

julia> a = [1, 2, 3, 4, 5] 5-element Array{Int64,1}: 1 2 3 4 5

Julia informs you ("5-element Array{Int64,1}") that you've created a 1-dimensional array with 5 elements, each of which is a 64-bit integer, and bound the variable  to it. Notice that intelligence is applied to the process: if one of the elements looks like a floating-point number, for example, you'll get an array of Float64s:

julia> a1 = [1, 2, 3.0, 4, 5] 5-element Array{Float64,1}: 1.0 2.0 3.0 4.0 5.0

Similarly for strings:

julia> s = ["this", "is", "an", "array", "of", "strings"] 6-element Array{String,1}: "this" "is" "an" "array" "of" "strings"

returns an array of strings, and:

julia> trigfuns = [sin, cos, tan] 3-element Array{Function,1}: sin cos tan returns an array of Julia functions.

There are many different ways to create arrays: you can make them empty, uninitialised, full, based on sequences, sparse, dense, and more besides. It depends on the task in hand.

Uninitialized
You can specify the type and the dimensions of an array using  (notice that upper-case "A"), putting the type in curly braces, and the dimensions in the parentheses. The  means that the array hasn't been initialized to known values.

julia> array = Array{Int64}(undef, 5) 5-element Array{Int64,1}: 4520632328 4614616448  4520668544  4520632328  4615451376 julia> array3 = Array{Int64}(undef, 2, 2, 2) 2×2×2 Array{Int64,3}: [:, :, 1] = 4452254272  4452255728  4452256400  4456808080 [:, :, 2] =  4456808816  4452255728  4456808816  4452254272

The random-looking numbers are a reminder that you've created an uninitialized array but haven't filled it with any sensible information.

Arrays of anything
It's possible to create arrays with elements of different types:

julia> [1, "2", 3.0, sin, pi] 5-element Array{Any, 1}: 1  "2"  3.0   sin π = 3.1415926535897...

Here, the array has five elements, but they're an odd mixture: numbers, strings, functions, constants — so Julia creates an array of type Any:

julia> typeof(ans) Array{Any,1}

Empty arrays
To create an array of a specific type, you can also use the type definition and square brackets:

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

If you think you can fool Julia by sneaking in a value of the wrong type while declaring a typed array, you'll be caught out:

julia> Int64[1, 2, 3, 4, 5, 6, 7, 8, 9, 10.1] ERROR: InexactError

You can create empty arrays this way too:

julia> b = Int64[] 0-element Array{Int64,1}

julia> b = String[] 0-element Array{String,1}

julia> b = Float64[] 0-element Array{Float64,1}

Creating 2D arrays and matrices
If you leave out the commas when defining an array, you can create 2D arrays quickly. Here's a single row, multi-column array:

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

Notice the  in the first row of the response.

You can use a semicolon to add another row:

julia> [1 2 3 4 ; 5 6 7 8] 2x4 Array{Int64,2}: 1 2  3  4 5  6  7  8

Row and column vectors
Compare these two:  and.

With the commas, this array could be called a "column vector", with 5 rows and 1 column:

julia> [1, 2, 3, 4, 5] 5-element Array{Int64,1}: 1 2 3 4 5

But with the spaces, this array could be called a "row vector", with 1 row and 5 columns:

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

- notice the  here, which tells you that this is a 2D array of Int64s (with 1 row and 5 columns). In both cases, they're standard Julia arrays.

Arrays created like this can be used as matrices:

julia> [1 2 3; 4 5 6] 2x3 Array{Int64,2}: 1 2  3 4  5  6

And of course you can create arrays/matrices with 3 or more dimensions.

There are a number of functions which let you create and fill an array in one go. See Creating and filling an array.

Notice how Julia distinguishes between  and  :

julia> x = rand(5) 5-element Array{Float64,1}: 0.4821773161183929  0.5811789456966778   0.7852806713801641   0.23626682918327369  0.6777187748570226

julia> x = rand(5, 1) 5×1 Array{Float64,2}: 0.0723474801859294  0.6314375868614579   0.21065681560040828  0.8300724654838343   0.42988769728089804

Julia provides the  and   constructor functions, but these are simply aliases for uninitialized one and two dimensional arrays:

julia> Vector(undef, 5) 5-element Array{Any,1}: #undef #undef #undef #undef #undef julia> Matrix(undef, 5, 5) 5x5 Array{Any,2}: #undef #undef  #undef  #undef  #undef #undef #undef  #undef  #undef  #undef #undef #undef  #undef  #undef  #undef #undef #undef  #undef  #undef  #undef #undef #undef  #undef  #undef  #undef

Creating arrays using range objects
In Julia, the colon has a number of uses. One use is to define ranges and sequences of numbers. You can create a range object by typing it directly:

julia> 1:10 1:10

It may not look very useful in that form, but it provides the raw material for any job in Julia that needs a range or sequence of numbers.

You can use it in a loop expression:

julia> for n in 1:10 print(n) end 12345678910

Or you can use  to build an array consisting of those numbers:

julia> collect(1:10) 10-element Array{Int64,1}: 1 2  3  4  5  6  7  8  9 10

You don't have to start and finish on an integer either:

julia> collect(3.5:9.5) 7-element Array{Float64,1}: 3.5 4.5 5.5 6.5 7.5 8.5 9.5 There's also a three-piece version of a range object, start:step:stop, which lets you specify a step size other than 1. For example, this builds an array with elements that go from 0 to 100 in steps of 10:

julia> collect(0:10:100) 11-element Array{Int64,1}: 0 10  20  30  40  50  60  70  80  90 100

To go down instead of up, you have to use a negative step value:

julia> collect(4:-1:1) 4-element Array{Int64,1}: 4 3  2  1

Instead of using  to create an array from the range, you could use the ellipsis  operator (three periods) after the last element:

julia> [1:6...] 6-element Array{Int64,1}: 1 2  3  4  5  6

(The  ellipsis is sometimes called the splat operator. It represents a sequence of arguments.)

However,  is faster and the recommended method of converting ranges to arrays. But you can use range objects in many situations in Julia, and you don't always need to expand them into arrays.

More range objects
Another useful function is, which constructs a range object that goes from a start value to an end value taking a specific number of steps of a certain size. You don't have to calculate all the information, because Julia calculates the missing pieces for you by combining the values for the keywords,  , and. For example, to go from 1 to 100 in exactly 12 steps:

julia> range(1, length=12, stop=100) 1.0:9.0:100.0

or take 10 steps from 1, stopping at or before 100:

julia> range(1, stop=100, step=10) 1:10:91

If you really want it in array form, you can use the range object to build an array:

julia> collect(range(1, length=12, stop=100)) 12-element Array{Float64,1}: 1.0 10.0  19.0  28.0  37.0  46.0  55.0  64.0  73.0  82.0  91.0 100.0

Notice that it provided you with a Float64 array, rather than an Integer array, even though the values could have been integers.

For logarithmic ranges (sometimes called 'log space'), you can use simple range objects and then broadcast the  function  to every element of the range.

julia> exp10.(range(2.0, stop=3.0, length=5)) 5-element Array{Float64,1}: 100.0               177.82794100389228   316.22776601683796   562.341325190349    1000.0

See Broadcasting and dot syntax.

Use  on a range object to find out what the step size is:

julia> step(range(1, length=10, stop=100)) 11.0

Use  if you know the start and step, but not the end, and you know how many elements you want:

julia> range(1, step=3, length=20) |> collect 20-element Array{Int64,1}: 1 4  7 10 13 16 19 22 25 28 31 34 37 40 43 46 49 52 55 58

Collecting up the values in a range
As you've seen, if you're not using your range object in a  loop, you can, if you want, use   to obtain all the values from a range object directly:

julia> collect(0:5:100) 21-element Array{Int64,1}: 0  5  10  15  20  25  30  35  40  45  50  55  60  65  70  75  80  85  90  95 100 However, you don't always have to convert ranges to arrays before working on them — you can usually iterate over things directly. For example, you don't have to write this:

1 2 3 4 5 6

because it works just as well (and probably faster) if you leave out the : 1 2 3 4 5 6

Using comprehensions and generators to create arrays
A useful way to create arrays where each element can be produced using a small computation is to use comprehensions (described in Comprehensions).

For example, to create an array of 5 numbers:

julia> [n^2 for n in 1:5] 5-element Array{Int64,1}: 1 4  9 16 25

With two iterators, you can easily create a 2D array or matrix:

julia> [r * c for r in 1:5, c in 1:5] 5x5 Array{Int64,2}: 1  2   3   4   5 2   4   6   8  10 3   6   9  12  15 4   8  12  16  20 5  10  15  20  25

You can add an  test at the end to filter (keep) values that pass a test:

julia> [i^2 for i=1:10 if i != 5] 9-element Array{Int64,1}: 1   4    9   16   36   49   64   81  100

Generator expressions are similar, and can be used in a similar way:

julia> collect(x^2 for x in 1:10) 10-element Array{Int64,1}: 1   4    9   16   25   36   49   64   81  100

julia> collect(x^2 for x in 1:10 if x != 1) 9-element Array{Int64,1}: 4   9   16   25   36   49   64   81  100

The advantage of generator expressions is that they generate values when needed, rather than build an array to hold them first.

Creating and filling an array
There are a number of functions that let you create arrays with specific contents. These can be very useful when you're using 2D arrays as matrices:

-  creates an array/matrix of zeros with m rows and n columns:

julia> zeros(2, 3) 2x3 Array{Float64,2}: 0.0 0.0  0.0 0.0  0.0  0.0

You can specify the type of the zeros if you want:

julia> zeros(Int64, 3, 5) 3×5 Array{Int64,2}: 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0

-  creates an array/matrix of ones with m rows and n columns

julia> ones(2, 3) 2x3 Array{Float64,2}: 1.0 1.0  1.0  1.0  1.0  1.0

-  creates an m-row by n-column matrix full of random numbers:

julia> rand(2, 3) 2×3 Array{Float64,2}: 0.488552  0.657078   0.895564  0.0190633  0.0120305  0.772106

-  creates a matrix full of numbers in the supplied range:

julia> rand(1:6, 3, 3) 3x3 Array{Int64,2}: 4 4  1  3  2  3  6  3  3

-  creates an m-row by n-column matrix full of normally-distributed random numbers with mean 0 and standard deviation 1.

As well as the,   functions, there are  ,  ,  , and   functions as well.

The  and   functions fill arrays with the Boolean values true or false:

julia> trues(3, 4) 3x4 BitArray{2}: true true  true  true true true  true  true true true  true  true

Notice how the result is a BitArray.

You can use  to create an array with a specific value, i.e. an array of repeating duplicates:

julia> fill(42, 9) 9-element Array{Int64,1}: 42 42 42 42 42 42 42 42 42 julia> fill("hi", 2, 2) 2x2 Array{String,2}: "hi" "hi" "hi" "hi"

With, the exclamation mark  or "bang" is to warn you that you're about to change the contents of an existing array (a useful indication that's adopted throughout Julia).

julia> a = zeros(10) 10-element Array{Float64,1}: 0.0 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0 julia> fill!(a, 42) 10-element Array{Float64,1}: 42.0 42.0  42.0  42.0  42.0  42.0  42.0  42.0  42.0  42.0

Let's change an array of falses to trues:

julia> trueArray = falses(3,3) 3x3 BitArray{2}: false false  false false false  false false false  false

julia> fill!(trueArray, true) 3x3 BitArray{2}: true true  true true true  true true true  true

julia> trueArray 3x3 BitArray{2}: true true  true true true  true true true  true You can use the  function to create vector-like arrays, followed by   to change them into 2D arrays:

julia> a = reshape(range(0, stop=100, length=30), 10, 3) 10×3 reshape(::StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}, 10, 3) with eltype Float64: 0.0     34.4828   68.9655   3.44828  37.931    72.4138   6.89655  41.3793   75.8621  10.3448   44.8276   79.3103  13.7931   48.2759   82.7586  17.2414   51.7241   86.2069  20.6897   55.1724   89.6552  24.1379   58.6207   93.1034  27.5862   62.069    96.5517  31.0345   65.5172  100.0

The result is a 10 by 3 array featuring evenly-spaced numbers between 0 and 100.

Repeating elements to fill arrays
A useful function for creating arrays by repeating smaller ones is.

The first option for its syntax is, the source array is repeated by   times in the first dimension (rows), and   times in the second (columns).

You don't have to supply the second dimension, just supply how many rows you want:

julia> repeat([1, 2, 3], 2) 6-element Array{Int64,1}: 1 2  3  1  2  3 julia> repeat([1 2 3], 2) 2x3 Array{Int64,2}: 1 2  3  1  2  3

The second option specifies the extra columns:

julia> repeat([1, 2, 3], 2, 3) 6x3 Array{Int64,2}: 1 1  1  2  2  2  3  3  3  1  1  1  2  2  2  3  3  3 julia> repeat([1 2 3], 2, 3) 2x9 Array{Int64,2}: 1 2  3  1  2  3  1  2  3  1  2  3  1  2  3  1  2  3

The  function also lets you create arrays by duplicating rows and columns of a source array. The  and   options determine whether rows and/or columns are repeated. For example,  makes an array with two copies of each row and three copies of each column:

julia> repeat([1, 2], inner = [2, 3]) 4x3 Array{Int64,2}: 1 1  1  1  1  1  2  2  2  2  2  2

By contrast, here's :

julia> repeat([1, 2], outer = [2, 3]) 4x3 Array{Int64,2}: 1 1  1  2  2  2  1  1  1  2  2  2

Note that the latter is equivalent to. A more meaningful example of the  keyword is when it is combined with. Here, each element of each line of the initial matrix is line-duplicated and then, each line slice of the resulting matrix is column-triplicated:

julia> repeat([1 2; 3 4], inner=(2, 1), outer=(1, 3)) 4×6 Array{Int64,2}: 1 2  1  2  1  2   1  2  1  2  1  2   3  4  3  4  3  4   3  4  3  4  3  4

Array constructor
The  function we saw earlier builds arrays of a specific type for you:

julia> Array{Int64}(undef, 6) 6-element Array{Int64,1}: 4454517776 4454517808  4454517840  4454517872  4454943824  4455998977

This is uninitialized; the odd-looking numbers are simply the old contents of the memory before it was assigned to hold the new array.

Arrays of arrays
It's easy to create an array of arrays. Sometimes you want to specify the original contents:

julia> a = Array1, 2], [3,4 2-element Array{Array,1}: [1, 2]    [3, 4]

The  constructor can also construct an array of arrays:

julia> Array[1:3, 4:6] 2-element Array{Array,1}: [1,2,3] [4,5,6] With the   function, you could of course just create a simple array and then change its shape:

julia> reshape([1, 2, 3, 4, 5, 6, 7, 8], 2, 4) 2x4 Array{Int64,2}: 1 3  5  7 2  4  6  8 The same techniques can be used to create 3D arrays. Here's a 3D array of strings:

julia> Array{String}(undef, 2, 3, 4) 2x3x4 Array{String,3}: [:, :, 1] =
 * 1) undef #undef  #undef
 * 2) undef #undef  #undef

[:, :, 2] =
 * 1) undef #undef  #undef
 * 2) undef #undef  #undef

[:, :, 3] =
 * 1) undef #undef  #undef
 * 2) undef #undef  #undef

[:, :, 4] = Each element is set to 'undefined' —.
 * 1) undef #undef  #undef
 * 2) undef #undef  #undef

The  function pushes another item onto the back of an array:

julia> push!(a, rand(1:100, 5)) 3-element Array{Array,1}: [1, 2] [3, 4] [4, 71, 82, 60, 48] julia> push!(a, rand(1:100, 5)) 4-element Array{Array,1}: [1,2] [3,4] [4, 71, 82, 60, 48] [4, 22, 52, 5, 14]

or you might want to create them empty:

julia> a = Array{Int}[] 0-element Array{Array{Int64,N} where N,1} julia> push!(a, [1, 2, 3]) 1-element Array{Array{Int64,N} where N,1}: [1, 2, 3] julia> push!(a, [4, 5, 6]) 2-element Array{Array{Int64,N} where N,1}: [1, 2, 3] [4, 5, 6]

You can use  as an alias for  :

julia> a = Vector{Int}1, 2], [3, 4 2-element Array{Array{Int64,1},1}: [1, 2] [3, 4] julia> push!(a, rand(1:100, 5)) 3-element Array{Array{Int64, 1},1}: [1, 2] [3, 4] [12, 65, 53, 1, 82] julia> a[2] 2-element Array{Int64,1}: 3 4 julia> a[2][1] 3

Copying arrays
If you have an existing array and want to create another array having the same dimensions, you can use the  function:

julia> a = collect(1:10); # hide the output with the semicolon

julia> b = similar(a) 10-element Array{Int64,1}: 4482975872 4482975792           1  4482975952  4482976032  4482976112           3           3           2  4520636161 Notice that the array dimensions are copied, but the values aren't, they've been copied from random bits of memory. You can, though, change the type and dimensions anyway, so they don't have to be that similar:

julia> c = similar(b, String, (2, 2)) 2x2 Array{String,2}:
 * 1) undef #undef
 * 2) undef #undef

And in any case there's a  function.

Matrix operations: using arrays as matrices
In Julia, a 2-D array can be used as a matrix. All the functions available for working on arrays can be used (if the dimensions and contents permit) as matrices.

A quick way of typing a matrix is to separate the elements using spaces (to make rows) and to use semicolons to separate the rows. So:

You could also do this:

julia> id = reshape([1, 2, 3, 4], 2, 2) 2×2 Array{Int64,2}: 1 3  2  4

which takes a standard array and reshapes it to run in two rows and two columns. Notice that the matrix is filled column by column.

If you don't use commas or semicolons:

julia> [1 2 3 4]

you'll create a single row array/matrix:

1x4 Array{Int64,2}: 1 2  3  4

In each case, notice the 2 in the braces following the type value. This indicates a 2-dimensional array.

You can create an array of arrays by sticking two arrays next to each other, like this:

julia> 1, 2, 3], [4, 5, 6 2-element Array{Array{Int64,1},1}: [1, 2, 3] [4, 5, 6]

When you omit the comma, you're placing columns next to each and you'll get this:

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

Accessing the contents of arrays
To access the elements of an array or matrix, follow the name of the array by the element number in square brackets. Here's a 1D array:

julia> a = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]

Here's the fifth element:

julia> a[5] 50

The first element is index number 1. Julia is one of the languages that starts indexing elements in lists and arrays starting at 1, rather than 0. (And thus it's in the elite company of Matlab, Mathematica, Fortran, Lua, and Smalltalk, while most of the other programming languages are firmly in the opposite camp of 0-based indexers.)

The last element is referred to as end (not -1, as in some other languages):

julia> a[end] 100

Similarly, you can access the second to last element with

julia> a[end-1] 90

(with similar syntax for the third to last element and so on).

You can provide a bunch of index numbers, enclosed in a pair of brackets at each end:

julia> a3,6,2 3-element Array{Int64,1}: 30 60  20

or supply a range of index numbers:

julia> a[2:2:end] 5-element Array{Int64,1}: 20  40   60   80  100

You can even select elements using  and   values:

julia> atrue, true, false, true, true, true, false, true, false, false 6-element Array{Int64,1}: 10 20  40  50  60  80

Here's a 2D array, with the rows separated by semicolons:

julia> a2 = [1 2 3; 4 5 6; 7 8 9] 3x3 Array{Int64,2}: 1 2  3 4  5  6 7  8  9 julia> a2[1] 1

If you just ask for one element of a 2D array, you'll receive it as if the array is unwound column by column, i.e. down first, then across. In this case you'll get 4, not 2:

julia> a2[2] 4

Asking for row then column works as you expect:

julia> a2[1, 2] 2

which is row 1, column 2. Here's row 1, column 3:

julia> a2[1, 3] 3

but don't get the row/column indices the wrong way round:

julia> a2[1, 4] ERROR: BoundsError: attempt to access 3×3 Array{Int64,2} at index [1, 4] Stacktrace: [1] getindex(::Array{Int64,2}, ::Int64, ::Int64) at ./array.jl:498

By the way, there's an alternative way of obtaining elements from arrays: the  function:

julia> getindex(a2, 1, 3) 3 julia> getindex(a2, 1, 4) ERROR: BoundsError: attempt to access 3×3 Array{Int64,2} at index [1, 4] Stacktrace: [1] getindex(::Array{Int64,2}, ::Int64, ::Int64) at ./array.jl:498

Use the colon to indicate every row or column. For example, here's "every row, second column":

julia> a2[:, 2] 3-element Array{Int64,1}: 2 5 8

and here's "second row, every column":

julia> a2[2, :] 3-element Array{Int64,1}: 4 5  6

Elementwise and vectorized operations
Many Julia functions and operators are designed specifically to work with arrays. This means that you don't always have to work through an array and process each element individually.

A simple example is the use of the basic arithmetic operators. These can be used directly on an array if the other argument is a single value:

julia> a = collect(1:10); julia> a * 2 10-element Array{Int64,1}: 2  4   6   8  10  12  14  16  18  20

and every element of the new array is the original multiplied by 2. Similarly:

julia> a / 100 10-element Array{Float64,1}: 0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.1

and every element of the new array is the original divided by 100.

These operations are described as operating elementwise.

Many operators can be used preceded with a dot. These versions are the same as their non-dotted versions, and work on the arrays element by element. For example, the multiply function can be used elementwise, using. This lets you multiply arrays or ranges together element by element:

julia> n1 = 1:6; julia> n2 = 100:100:600; julia> n1 .* n2 6-element Array{Int64,1}: 100 400  900 1600 2500 3600

and the first element of the result is what you get by multiplying the first elements of the two arrays, and so on.

As well as the arithmetic operators, some of the comparison operators also have elementwise versions. For example, instead of using  in a loop to compare two arrays, use. Here are two arrays of ten numbers, one sequential, the other disordered, and an elementwise comparison to see how many elements of array  happened to end up in the same place as array  :

julia> a = 1:10; b=rand(1:10, 10); a .== b 10-element BitArray{1}: true false true false false false false false false false

Broadcasting: dot syntax for vectorizing functions
This technique of applying functions elementwise to arrays with the dot syntax is called broadcasting. Follow the function name with a dot/period before the opening parenthesis, and supply an array or range as an argument. For example, here's a simple function which multiplies two numbers together:

julia> f(a, b) = a * b f (generic function with 1 method) It works as expected on two scalars:

julia> f(2, 3) 6

But it's easy to apply this function to an array. Just use the dot syntax:

julia> f.([1, 4, 2, 8, 7], 10) 5-element Array{Int64,1}: 10 40  20  80  70

julia> f.(100, 1:10) 10-element Array{Int64,1}: 100  200   300   400   500   600   700   800   900  1000

In the first example, Julia automatically treated the second argument as if it was an array, so that the multiplication would work correctly.

Watch out for this when combining ranges and vectorized functions:

julia> 0:10 .* 0.5 |> collect 6-element Array{Float64,1}: 0.0 1.0  2.0  3.0  4.0  5.0 julia> 0.5 .* 0:10  |> collect 11-element Array{Float64,1}: 0.0  1.0   2.0   3.0   4.0   5.0   6.0   7.0   8.0   9.0  10.0

The first example is equivalent to, and you might have intended.

min and max
Watch out for  and. You might think that  can be used on an array, like this, to find the largest element:

julia> r = rand(0:10, 10) 10-element Array{Int64,1}: 3 8  4  3  2  5  7  3 10 10

but no…

julia>  max(r)  LoadError: MethodError: no method matching max(::Array{Int64,1}) ...

The  function returns the largest of its arguments. To find the largest element in an array, you can use the related function :

julia>  maximum(r)  10

You can use  on two or more arrays to carry out an elementwise examination, returning another array containing the maximum values:

julia> r = rand(0:10, 10); s = rand(0:10, 10); t = rand(0:10,10);

julia> max(r, s, t) 10-element Array{Int64,1}: 8 9  7  5  8  9  6 10  9  9

and  behave in a similar way.

A way to make max work on an array is to use the ellipsis (splat) operator:

julia> max(r...) 9

You can test each value of an array and change it in a single operation, using element-wise operators. Here's an array of random integers from 0 to 10:

julia> a = rand(0:10,10, 10) 10x10 Array{Int64,2}: 10  5   3   4  7   9  5   8  10   2  6  10   3   4  6   1  2   2   5  10  7   0   3   4  1  10  7   7   0   2  4   9   5   2  4   2  1   6   1   9  0   0   6   4  1   4  8  10   1   4 10   4   0   5  1   0  4   4   9   2  9   4  10   9  6   9  4   5   1   1  1   9  10  10  1   9  3   2   3  10  4   6   3   2  7   7  5   4   6   8  3   8   0   7  1   0  1   9   7   5

Now you can test each value for being equal to 0, then set only those elements to 11, like this: julia> a[a .== 0] .= 11;

julia> a 10x10 Array{Int64,2}: 10  5   3   4  7   9  5   8  10   2  6  10   3   4  6   1  2   2   5  10  7  11   3   4  1  10  7   7  11   2  4   9   5   2  4   2  1   6   1   9 11  11   6   4  1   4  8  10   1   4 10   4  11   5  1  11  4   4   9   2  9   4  10   9  6   9  4   5   1   1  1   9  10  10  1   9  3   2   3  10  4   6   3   2  7   7  5   4   6   8  3   8  11   7  1  11  1   9   7   5

This works because  returns an array of   and   values, and these are then used to select the elements of   which are to be set to 11.

If you're doing arithmetic on 2D matrices, you might want to read more about matrix arithmetic: Matrix arithmetic

Rows and Columns
With a 2D array, you use brackets, colons, and commas to extract individual rows and columns or ranges of rows and columns.

With this table:

julia> table = [r * c for r in 1:5, c in 1:5] 5x5 Array{Int64,2}: 1  2   3   4   5 2   4   6   8  10 3   6   9  12  15 4   8  12  16  20 5  10  15  20  25

you can find a single row using the following (notice the comma):

julia> table[1, :] 1x5 Array{Int64,2}: 5-element Array{Int64,1}: 1 2  3  4  5

and you can get a range of rows with a range followed by a comma and a colon:

julia> table[2:3,:] 2x5 Array{Int64,2}: 2 4  6   8  10 3  6  9  12  15

To select columns, start with a colon followed by a comma:

julia> table[:, 2] 5-element Array{Int64,1}: 2 4  6  8 10

On its own, the colon accesses the entire array:

julia> table[:] 25-element Array{Int64,1}: 1 2  3  4  5  2  4  6  8 10  3  6  9 12 15  4  8 12 16 20  5 10 15 20 25

To extract a range of columns:

julia> table[:, 2:3] 5x2 Array{Int64,2}: 2  3  4   6  6   9  8  12 10  15

Finding items in arrays
If you want to know whether an array contains an item, use the  function, which can be called in two ways:

julia> a = 1:10

julia> 3 in a true

Or phrased as a function call:

julia> in(3, a) # needle ... haystack true

There's a set of functions starting with find — such as,  ,  ,   and   — that you can use to get the index or indices of array cells that match a specific value, or pass a test. Each of these has two or more more forms. Here's an array of small primes:

julia> smallprimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29];

To find the first occurrence of a number, and obtain its index, you can use the following method of the  function:

julia> findfirst(isequal(13), smallprimes) 6

so the first occurrence of 13 in the array is in the sixth cell:

julia> smallprimes[6] 13

This function is similar to many in Julia which accepts a function as the first argument. The function is applied to each element of an array, and if the function returns true, that element or its index is returned. This function returns the index of the first element.

Here's another example using an anonymous function:

julia> findfirst(x -> x == 13, smallprimes) 6

The  function returns an array of indices, pointing to every element where the function returns true when applied:

julia> findall(isinteger, smallprimes) 10-element Array{Int64,1}: 1 2  3  4  5  6  7  8  9 10

julia> findall(iseven, smallprimes) 1-element Array{Int64,1}: 1

Remember that these are arrays of index numbers, not the actual cell values. The indices can be used to extract the corresponding values using the standard square bracket syntax:

julia> smallprimes[findall(isodd, smallprimes)] 9-element Array{Int64,1}: 3 5  7 11 13 17 19 23 29

whereas  returns a single number — the index of the first matching cell:

julia> findfirst(iseven, smallprimes) 1

julia> smallprimes[findfirst(iseven, smallprimes)] 2

The  function is very similar to the   and   functions, but accepts an additional number that tells the functions to start the search from somewhere in the middle of the array, rather than from the beginning. For example, if  finds the index of the first occurrence of the number 13 in the array, we can continue the search from there by using this value in  :

julia> findnext(isodd, smallprimes, 1 + findfirst(isequal(13), smallprimes)) 7

julia> smallprimes[ans] 17

To return the indices of the elements in array B where the elements of array A can be found, use :

julia> findall(in([11, 5]), smallprimes) 2-element Array{Int64,1}: 3 5 julia> smallprimes[3] 5 julia> smallprimes[5] 11

The order in which the indices are returned should be noted.

Finding out about an array
With our 2D array:

julia> a2 = [1 2 3; 4 5 6; 7 8 9] 3x3 Array{Int64,2}: 1 2  3 4  5  6 7  8  9

we can find out more about it using the following functions:



returns the number of dimensions, i.e. 1 for a vector, 2 for a table, and so on:

julia> ndims(a2) 2

returns the row and column count of the array, in the form of a tuple:

julia> size(a2) (3,3)

tells you how many elements the array contains:

julia> length(a2) 9

You can use  to find out how many times a particular value occurs. For example, how many non-zero items are there?

julia> count(!iszero, a2) 9

For finding the inverse, determinant and other aspects of an array/matrix, see Manipulating matrices.

To convert between index numbers (1 to ) and row/column numbers (1:, 1: ), you can use:

julia> CartesianIndices(a2)[6] CartesianIndex(3, 2)

to find the row and column for the sixth element, for example.

And to go in the other direction, what index number corresponds to row3, column 2? Use the opposite of Cartesian indices, Linear indices:

julia> LinearIndices(a2)[3, 2] 6

is useful to find the differences between each element of an array:

julia> [2x for x in 1:10]  10-element Array{Int64,1}: 2  4   6   8  10  12  14  16  18  20 julia> [2x for x in 1:10] |> diff 9-element Array{Int64,1}: 2 2  2  2  2  2  2  2  2

Comparing arrays
builds a new array that's the union or combination of two or more arrays. The operation removes duplicates, and the result contains a single version of each element:

julia> odds = collect(1:2:10) 5-element Array{Int64,1}: 1 3 5 7 9

julia> evens = collect(2:2:10) 5-element Array{Int64,1}: 2 4  6  8 10

julia> union(odds, evens) 10-element Array{Int64,1}: 1 3  5  7  9  2  4  6  8 10

Notice that the ordering of the new union reflects the original order. This example doesn't sort the numbers at all: julia> union(1:5, 1:10, 5:-1:-5) 16-element Array{Int64,1}: 1 2  3  4  5  6  7  8  9 10  0 -1 -2 -3 -4 -5

returns a new array that's the intersection of two or more arrays. The result contains one occurrence of each element, but only if it occurs in every array:

julia> intersect(1:10, 5:15) 5:10

julia> intersect(5:20, 1:15, 3:12) 5:12

finds the difference between two arrays, i.e. the elements that are in the first array but not the second:

julia> setdiff(1:15, 5:20) 4-element Array{Int64,1}: 1 2 3 4

julia> setdiff(5:20, 1:15) 5-element Array{Int64,1}: 16 17 18 19 20

Filtering
There's a set of related functions that let you work on an array's elements.

finds and keeps elements if they pass a test. Here, we're using the  function (passing it as a named function without parentheses, rather than a function call with parentheses) to filter (keep) everything in the array that's odd.

julia> filter(isodd, 1:10) 5-element Array{Int64,1}: 1 3  5  7  9 Like many Julia functions, there's a version which changes the array. So  returns a copy of the original, but   changes the array.

The  function we met earlier is like , but just counts the number of elements that satisfy the condition:

julia> count(isodd, 1:100) 50

Also, the  function just tells you whether any of the elements satisfy the condition:

julia> any(isodd, 1:100) true

and the  function tells you if all of the elements satisfy the condition. Here,  checks to see whether   did the job properly.

julia> all(isodd, filter(isodd, 1:100)) true

Random element of an array
To choose a random element from an array:

julia> a = collect(1:100); julia> a[rand(1:end)] 14

Other functions
Because arrays are fundamental to Julia, there are dozens of array-handling functions that can't be described here. But here are a few selections:

Find the extreme values of an array:

julia> a = rand(100:110, 10) 10-element Array{Int64,1}: 109 102  104  108  103  110  100  108  101  101

julia> extrema(a) (100,110)

finds the maximum element and returns it and its index in a tuple:

julia> findmax(a) (110,6)

Use  to return just the index.

The  and   functions let you supply functions to determine how the "maximum" is determined. This is useful if your arrays are not simple vectors. This example find the maximum array element, where maximum here means, "has the largest last value":

julia> maximum(x -> last(x), [(1, 2), (2, 23), (8, 12), (7, 2)]) 23

Functions such as,  ,  ,  , do what you would expect:

( and   have been moved into the Statistics module in the standard library; you may need to first enter "using Statistics" to use them)

julia> sum(a) 1046

julia> prod(1:10) 3628800

julia> mean(a) 104.6

julia> middle(a) 105.0

,, and   also let you supply functions: the function is applied to each element and then the results are summed/mean-ed/prod-ded:

julia> sum(sqrt, 1:10) # the sum of the square roots of the first 10 integers 22.4682781862041 julia> mean(sqrt, 1:10) # the mean of the square roots of the first 10 integers 2.24682781862041

There are functions in the Combinatorics.jl package that let you find combinations and permutations of arrays. finds all the possible combinations of elements in an array: you can specify how many elements in each combination: julia> ] (v1.0) pkg> add Combinatorics # (do this just once) julia> using Combinatorics julia> collect(combinations(a, 3)) 120-element Array{Array{Int64,1},1}: [109,102,104] [109,102,108]  [109,102,103]  [109,102,110]  [109,102,100]  [109,102,108]  [109,102,101]  [109,102,101]  [109,104,108]  [109,104,103]  [109,104,110]  [109,104,100]  [109,104,108]  ⋮              [103,108,101]  [103,101,101]  [110,100,108]  [110,100,101]  [110,100,101]  [110,108,101]  [110,108,101]  [110,101,101]  [100,108,101]  [100,108,101]  [100,101,101]  [108,101,101]

and  generates all permutations. There are a lot — in practice you probably won't need to use  to collect the items into an array:

julia> length(permutations(a)) 3628800

Modifying array contents: adding and removing elements
To add an item at the end of an array, use :

julia> a = collect(1:10); push!(a, 20) 11-element Array{Int64,1}: 1 2  3  4  5  6  7  8  9 10 20

As usual, the exclamation mark reminds you that this function changes the array. You can push only onto the end of vectors.

To add an item at the front, use :

julia> pushfirst!(a, 0) 12-element Array{Int64,1}: 0 1  2  3  4  5  6  7  8  9 10 20

To insert an element into an array at a given index, use the  function. For example, here's a list of numbers with an obvious omission:

julia> a = [1, 2, 3, 5, 6, 7, 8, 9] 8-element Array{Int64,1}: 1 2 3 5 6 7 8 9

Use  to insert a sequence at a specific range of index values. Julia returns the values that were replaced. The array grows larger to accommodate the new elements, and elements after the inserted sequence are pushed down. Let's insert, at position 4:5, the range of numbers :

julia> splice!(a, 4:5, 4:6) 2-element Array{Int64,1}: 5 6

You'll be tempted to check that the new values were inserted correctly:

julia> a 9-element Array{Int64,1}: 1 2  3  4  5  6  7  8  9

Now, if you want to insert some values at a specific inter-index location, you will have to use a feature known as empty ranges. In this case the interspace between indexes n-1 and n is denoted as.

For example: julia> L = ['a','b','f'] 3-element Array{Char,1}: 'a' 'b'  'f'

julia> splice!(L, 3:2, ['c','d','e']) 0-element Array{Char,1}

julia> L 6-element Array{Char,1}: 'a' 'b'  'c'  'd'  'e'  'f'

Removing elements
If you don't supply a replacement, you can also use  can remove elements and move the rest of them along.

julia> a = collect(1:10);  julia> splice!(a,5); julia> a 9-element Array{Int64,1}: 1 2  3  4  6  7  8  9 10

To remove the last item:

julia> pop!(a) 10

and the first:

julia> popfirst!(a) 1

More aggressive modification of arrays (and similar data structures) can be made with functions such as  and. You can find out the indices of elements in various ways. Once you know the indices, you can use  to delete an element, given its index number:

julia> a = collect(1:10);

julia> findfirst(isequal(6), a) 6

julia> deleteat!(a, findfirst(isequal(6), a)) 9-element Array{Int64,1}: 1 2  3  4  5  7  8  9 10

also accepts a range or iterator to specify the indices, so you can do this:

julia> deleteat!(a, 2:6) 4-element Array{Int64,1}: 1  8   9  10

Remember that you can always remove a group of elements using a filter: see Filtering.

Other functions
If you want to do something to an array, there's probably a function to do it, and sometimes with an exclamation mark to remind you of the potential consequences. Here are a few more of these array-modifying functions:


 * change the length of a Vector
 * push a second collection at the back of the first one
 * insert elements at the beginning of the first Vector
 * remove all elements
 * remove duplicate elements from the array "a" without overwriting the array.
 * remove duplicate elements from the array "a" and overwrites the array.
 * make a copy of an array rotated 90 degrees clockwise:

julia> rotr90([1 2 3 ; 4 5 6]) 3x2 Array{Int64,2}: 4 1 5  2 6  3


 * move the elements around 'in a circle' by a number of steps:

julia> circshift(1:6, 1) 6-element Array{Int64,1}: 6 1  2  3  4  5

This function can also do circular shifts on 2D arrays too. For example, here's a table:

julia> table = collect(r*c for r in 1:5, c in 1:5) 5×5 Array{Int64,2}: 1  2   3   4   5  2   4   6   8  10  3   6   9  12  15  4   8  12  16  20  5  10  15  20  25

By supplying a tuple you can move rows and columns. For example: moving the columns by 0 and the rows by 1 moves the first dimension by 0 and the second by 1. The first dimension is downwards, the second rightwards:

julia> circshift(table, (0, 1)) 5×5 Array{Int64,2}: 5 1   2   3   4  10  2   4   6   8  15  3   6   9  12  20  4   8  12  16  25  5  10  15  20

There's a modifying version of ,

Setting the contents of arrays
To set the contents of an array, specify the indices on the left-hand side of an assignment expression:

julia> a = collect(1:10); julia> a[9]= -9 -9

To check that the array has really changed:

julia> print(a) [1,2,3,4,5,6,7,8,-9,10]

You can set a bunch of elements at the same time, using the broadcasting assignment operator:

julia> a[3:6] .= -5 4-element view(::Array{Int64,1}, 3:6) with eltype Int64: -5 -5  -5  -5 julia> print(a) [1,2,-5,-5,-5,-5,7,8,-9,10]

And you can set a sequence of elements to a suitable sequence of values:

julia> a[3:9] = collect(9:-1:3) 7-element Array{Int64,1}: 9 8 7 6 5 4 3

Notice here that, although Julia shows the 7 element slice as the return value, in fact the whole array has been modified:

julia> a 10-element Array{Int64,1}: 1 2  9  8  7  6  5  4  3 10

You can set ranges to a single value in one operation using broadcasting:

julia> a[1:5] .= 0 0

julia> a 10-element Array{Int64,1}: 0  0   0   0   0   6   7   8   9  10

julia> a[1:10] .= -1; -1

julia> print(a) [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1]

As an alternative to the square bracket notation, there's a function call version that does the same job of setting array contents, :

julia> setindex!(a, 1:10, 10:-1:1) 10-element Array{Int64,1}: 10 9  8  7  6  5  4  3  2  1

You can refer to the entire contents of an array using the colon separator without start and end index numbers, i.e. . For example, after creating the array  :

julia> a = collect(1:10);

we can refer to the contents of this array  using  :

julia> b = a[:] 10-element Array{Int64,1}: 1 2  3  4  5  6  7  8  9 10 julia> b[3:6] 4-element Array{Int64,1}: 3 4 5 6

Passing arrays to functions
A function can't modify a variable passed to it as an argument, but it can change the contents of a container passed to it.

Consider the following function, that changes its argument to 5:

julia> x = 3 3

julia> set_to_5(x) 5

julia> x 3

Although the  inside the function is changed, the   outside the function isn't. Variable names in functions are local to the function.

But, you can modify the contents of a container, such as an array. The next function uses the  syntax to access the contents of the container , rather than change the value of the variable  :

If, instead of accessing the container variable's contents, you try to change the variable itself, it won't work. For example, the following function definition creates an array of 5s in  and then attempts to change the argument   to be.

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

julia> fail_to_fill_with_5(x) 10-element Array{Int64,1}: 5 5 5 5 5 5 5 5 5 5

It looks like it worked, but:

julia> x 10-element Array{Int64,1}: 1 2  3  4  5  6  7  8  9 10

You can change elements of the array, but you can't change the variable so that it points to a different array. In other words, your function isn't allowed to change the binding between the argument and the array that was passed to it.

Julia's way of handling function arguments is described as “pass-by-sharing”. An array isn't copied when you pass it to a function (that would be very inefficient for large arrays).

Matrix arithmetic
For matrix-on-matrix arithmetic action, you can:

- add (+) and subtract (-):

- multiply (*), assuming the dimensions are compatible, so  is possible if. Note the difference between matrix multiplication and elementwise matrix multiplication. Here's a matrix :

and here's matrix :

The  broadcasting operator multiplies them elementwise:

Compare this with matrix multiplication, : which is:

julia> [1 * 10 + 2 * 12       1 * 11 + 2 * 13  ;      3 * 10 + 4 * 12     3 * 11 + 4 * 13] 2x2 Array{Int64,2}: 34 37   78  85

- division of two matrices. You can use the backslash (\) for left division:

julia> A = rand(1:9, 3, 3) 3x3 Array{Int64,2}: 5 4  3   8  7  7   9  3  7

julia> B = rand(1:9, 3, 3) 3x3 Array{Int64,2}: 6 5  5   6  7  5   7  2  7

julia> A \ B 3x3 Array{Float64,2}: 2.01961   0.411765   1.84314 0.254902   1.35294   -0.0392157   -1.70588   -0.823529  -1.35294

and the forward slash (/) right or slash division:

julia> A / B 3x3 Array{Float64,2}: 4.0      -2.0       -1.0      0.285714   0.714286   0.285714 5.07143   -3.07143   -0.428571

With a matrix and a scalar, you can add, subtract, multiply, and divide:

julia> A + 1 3x3 Array{Int64,2}: 6 5  4   9  8  8  10  4  8

julia> [1 2 3 4 5] * 2 1x5 Array{Int64,2}: 2 4  6  8  10

julia> A .- 1 3x3 Array{Int64,2}: 4 3  2  7  6  6  8  2  6

julia> A .* 2 3x3 Array{Int64,2}: 10  8   6  16  14  14  18   6  14

julia> A ./ 2 3x3 Array{Float64,2}: 2.5 2.0  1.5  4.0  3.5  3.5  4.5  1.5  3.5

and more besides:

julia> A // 2 3x4 Array{Rational{Int64},2}: 1//2 2//1  7//2   5//1  1//1  5//2  4//1  11//2  3//2  3//1  9//2   6//1

julia> A .< 6 3x3 BitArray{2}: true  true   true false false  false false  true  false

You can multiply matrix and a vector (the matrix-vector product), if the arrays have compatible shapes. Here's the matrix A:

and here's a vector V:

The  operator multiplies them:

The dot or inner product (aTb) can be found using the  function, but you'll have to import the LinearAlgebra library first:

julia> using LinearAlgebra

julia> (1 * 21) + (2 * 22) + (3 * 23) 134

The two arguments must have the same length. You can also use the dot operator, which you can obtain in the REPL by typing "\cdot" followed by a tab:

julia> [1:3] ⋅ [21:23] 134

Joining arrays and matrices
You can use  and   to join matrices together, if their dimensions permit.

keeps the first dimension and extends (joins) in the second,  keeps the second dimension and extends the first.

Here are two 3 by 4 matrices: julia> A = reshape(1:12, 3, 4) 3x4 Array{Int64,2}: 1 4  7  10  2  5  8  11  3  6  9  12

julia> B = reshape(100:100:1200, 3, 4) 3x4 Array{Int64,2}: 100 400  700  1000  200  500  800  1100  300  600  900  1200

makes a new array that still has 3 rows, but extends/joins the columns to make 8 in total:

julia> hcat(A, B) 3x8 Array{Int64,2}: 1 4  7  10  100  400  700  1000  2  5  8  11  200  500  800  1100  3  6  9  12  300  600  900  1200

makes a new array that keeps the 4 columns, but extends to 6 rows:

julia> vcat(A, B) 6x4 Array{Int64,2}: 1   4    7    10    2    5    8    11    3    6    9    12  100  400  700  1000  200  500  800  1100  300  600  900  1200

You'll probably find the shortcuts useful:


 * [A ; B ] is
 * [A  B ] is

flattens a matrix into a vector, turning it into a (what some call a 'column') vector:

julia> vec(ones(3, 4)) 12-element Array{Float64,1}: 1.0 1.0  1.0  1.0  1.0  1.0  1.0  1.0  1.0  1.0  1.0  1.0

There's also an  function  that does both.

You can use  to convert an array of arrays to a matrix (using the hcat-splat):

julia> a = Array1, 2], [3, 4], [5, 6 3-element Array{Array{T,N},1}: [1, 2] [3, 4]  [5, 6] julia> hcat(a...) 2x3 Array{Int64,2}: 1 3  5  2  4  6 Julia arrays are 'column-major'. This means that you read down the columns:

1 3  2  4

whereas 'row-major' arrays are to be read across, like this:

1 2  3  4

Column-major order is used in Fortran, R, Matlab, GNU Octave, and by the BLAS and LAPACK engines (the "bread and butter of high-performance numerical computation"). Row-major order is used in C/C++, Mathematica, Pascal, Python, C#/CLI/.Net and others.

Growing or extending arrays
Often you want to create an array and then add more to it, or 'grow' it. While can do this with  and , be aware that both these operations create new temporary arrays and copy elements, so they don't always produce the fastest code. A better way is to use. This is an efficient operation that extends the array. You can reshape the array later:

julia> a = [] julia> for i = 1:80 push!(a, i) end julia> a 80-element Array{Any,1}: 1  2   3   4   5   6   7   8   9   ⋮  75  76  77  78  79  80

lets you change the dimensions of an array. You can supply the dimensions or use a colon to ask Julia to calculate valid dimensions:

julia> reshape(a, 10, :) 10x8 Array{Any,2}: 1 11  21  31  41  51  61  71   2  12  22  32  42  52  62  72   3  13  23  33  43  53  63  73   4  14  24  34  44  54  64  74   5  15  25  35  45  55  65  75   6  16  26  36  46  56  66  76   7  17  27  37  47  57  67  77   8  18  28  38  48  58  68  78   9  19  29  39  49  59  69  79  10  20  30  40  50  60  70  80

would have the same effect.

doesn't let you push new rows to a 2D array or matrix. The best way to do the job is to work on a 1D array, as above, adding more elements at the end, and then use  to convert it to two dimensions. If necessary, use  to flip the matrix.

Manipulating matrices
To transpose an array or matrix, there's an equivalent  operator for the   function, to swap rows and columns:

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

julia> transpose(M) 4x3 Array{Int64,2}: 1  2   3   4   5   6   7   8   9  10  11  12

julia> M'  4x3 Array{Int64,2}: 1  2   3   4   5   6   7   8   9  10  11  12

To find the determinant of a square matrix, use, after remembering to load the LinearAlgebra library.

julia> using LinearAlgebra julia> A = rand(2:10, 3, 3) 3x3 Array{Int64,2}: 8 8   2  6  9   6  9  2  10

julia> det(A) 438.00000000000006

(in the Standard Library) finds the inverse of a square matrix, if it has one. (If the determinant of the matrix is zero, it won't have an inverse.)

julia> inv(A) 3x3 Array{Float64,2}: 0.178082  -0.173516   0.0684932  -0.0136986   0.141553  -0.0821918  -0.157534    0.127854   0.0547945

finds the rank of the matrix, and  finds the basis for the nullspace.

julia> A 3x4 Array{Int64,2}: 1 4  7  10  2  5  8  11  3  6  9  12

julia> rank(A) 2

julia> nullspace(A) 4x2 Array{Float64,2}: -0.475185 -0.272395   0.430549   0.717376   0.564458  -0.617566  -0.519821   0.172585

sums the diagonal of a square matrix (trace):

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

julia> tr(s) 15

Applying functions to matrices
There are a number of functions that can be applied to a matrix:

-  adds every element:

julia> A = reshape(1:9, 3, 3) 3×3 Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}}: 1 4  7  2  5  8  3  6  9

julia> sum(A) 45

You can specify a dimension if you want to sum just columns or rows. So to sum columns, specify dimension 1:

julia> sum(A, dims=(1)) 1x3 Array{Int64,2}: 6 15  24

To sum rows, specify dimension 2:

julia> sum(A, dims=(2)) 3x1 Array{Int64,2}: 12 15  18

-  finds the mean of the values in the matrix:

julia> using Statistics; mean(A) 5.0

As with, you can specify a dimension, so that you can find the mean of columns (use dimension 1) or rows (use dimension 2):

julia> mean(A, dims=(1)) 1x3 Array{Float64,2}: 2.0 5.0  8.0

julia> mean(A, dims=(2)) 3x1 Array{Float64,2}: 4.0 5.0  6.0

- the  and   functions compare two (or more) arrays element by element, returning a new array with the largest (or smallest) values from each:

julia> A = rand(-1:2:1, 3, 3) 3x3 Array{Int64,2}: -1 -1  -1  -1   1   1   1  -1   1 julia> B = rand(-2:4:2, 3, 3) 3x3 Array{Int64,2}: 2  2  2  2  -2  2  2   2  2 julia> min.(A, B) 3×3 Array{Int64,2}: 1 -2  -2 -1  -2  -1  1   1  -1 julia> max.(A, B) 3×3 Array{Int64,2}: 2 1  1 2  1  2 2  2  2

multiplies a matrix's elements together:

julia> A = reshape(collect(BigInt(1):25), 5, 5) 5×5 Array{BigInt,2}: 1  6  11  16  21  2   7  12  17  22  3   8  13  18  23  4   9  14  19  24  5  10  15  20  25 julia> prod(A) 15511210043330985984000000

(Notice the use of, products are very large.)

You can specify a dimension if you want to multiply just columns or rows. To multiply the elements of columns together, specify dimension 1; for rows, use dimension 2:

julia> prod(A, dims=1) 1x5 Array{Int64,2}: 120 30240  360360  1860480  6375600

julia> prod(A, dims=2) 5x1 Array{Int64,2}: 22176  62832  129168  229824  375000

Matrix norms
Most of these functions live in the LinearAlgebra library:

julia> using LinearAlgebra

Vector norms
The Euclidean norm, $$\|x\|_2 = \sqrt{x_1^2 + x_2^2 + \ldots + x_n^2}$$, is found by :

julia> X = [2, 4, -5] 3-element Array{Int64,1}: 2  4  -5 julia> LinearAlgebra.norm(X) # Euclidean norm 6.708203932499369 julia> LinearAlgebra.norm(X, 1) # 1-norm of the vector, the sum of element magnitudes 11.0

If X is a 'row' vector:

julia> X = [2 4 -5] 1x3 Array{Int64,2}: 2 4  -5 julia> LinearAlgebra.norm(X) 6.708203932499369 julia> LinearAlgebra.norm(X, 1) 11.0

The Euclidean distance between vectors $$x$$ and $$y$$, given by $$\|x - y\|_2$$, is found by :

julia> LinearAlgebra.norm([1 2 3] - [2 4 6]) 3.741657386773941 julia> LinearAlgebra.norm([1, 2, 3] - [2, 4, 6]) 3.741657386773941

The angle between two vectors $$a$$ and $$b$$ is $$\arccos\left(\frac{a^Tb}{\|a\|_2 \|b\|_2}\right)$$:

acos(dot(a,b)/(norm(a)*norm(b)))

Matrix norms
Here's the 1-norm of a matrix (the maximum absolute column sum):

julia> B = [5 -4 2 ; -1 2 3; -2 1 0] 3x3 Array{Int64,2}: 5 -4  2  -1   2  3  -2   1  0

julia> LinearAlgebra.opnorm(B, 1) 8.0

And here's the infinity norm (the maximum absolute row sum):

julia> LinearAlgebra.opnorm(B, Inf) 11.0

Note they are different from vectorized 1-norm or infinity norm:

julia> LinearAlgebra.norm(B, 1) 20.0

julia> LinearAlgebra.norm(B, Inf) 5.0

The Euclidean  is the default:

julia> LinearAlgebra.norm([2 3 ; 4 6]), LinearAlgebra.opnorm([2 3 ; 4 6]), sqrt(2^2 + 3^2 + 4^2 + 6^2) (8.062257748298547,8.062257748298547,8.06225774829855)

Scaling and rotating matrices
-  scales every element of the matrix in place by a scale factor  :

julia> A = [1 2 3      4 5 6               7 8 9]  3×3 Array{Int64,2}: 1 2  3  4  5  6  7  8  9 julia> rmul!(A, 2) 3×3 Array{Int64,2}: 2  4   6   8  10  12  14  16  18

There are rotation and circular-shifting functions too:

julia> A = [1 2 3      4 5 6               7 8 9]  3×3 Array{Int64,2}: 1 2  3  4  5  6  7  8  9

julia> rot180(A) 3×3 Array{Int64,2}: 9 8  7  6  5  4  3  2  1

julia> circshift(A, (1, 1)) 3×3 Array{Int64,2}: 9 7  8  3  1  2  6  4  5

julia> A 3×3 Array{Int64,2}: 1 2  3  4  5  6  7  8  9  makes a copy of a matrix reversing rows or columns:

julia> reverse(A, dims=(1)) 3×3 Array{Int64,2}: 7 8  9  4  5  6  1  2  3

julia> reverse(A, dims=(2)) 3×3 Array{Int64,2}: 3 2  1  6  5  4  9  8  7

and  can be used to change the dimensions of a matrix. For example, this is how you can use  to collapse a row vector (1 by 4) into a 4 by 1 array:

julia> a = [1 2 3 4] 1x4 Array{Int64,2}: 1 2  3  4

julia> ndims(a) 2

julia> b = squeeze(a, dims=(1)) 4-element Array{Int64,1}: 1 2  3  4

julia> ndims(b) 1

Sorting arrays
Julia has a flexible  function that returns a sorted copy of an array, and a companion   version that changes the array so that it's sorted.

You can usually use  without options and obtain the results you'd hoped for:

julia> using Random julia> rp = randperm(10) 10-element Array{Int64,1}: 6 4  7  3 10  5  8  1  9  2

julia> sort(rp) 10-element Array{Int64,1}: 1 2  3  4  5  6  7  8  9 10

You can sort 2D arrays:

julia> a = reshape(rand(1:20, 20), 4, 5) 4x5 Array{Int64,2}: 19 13   4  10  10  6  20  19  18  12 17   7  15  14   9  1  16   8   7  13

julia> sort(a, dims=(1)) # sort each column, dimension 1 4x5 Array{Int64,2}: 1  7   4   7   9  6  13   8  10  10 17  16  15  14  12 19  20  19  18  13

julia> sort(a, dims=(2)) # sort each row, dimension 2 4x5 Array{Int64,2}: 4 10  10  13  19 6  12  18  19  20 7   9  14  15  17 1   7   8  13  16

although there are more powerful alternatives in  and   — see below for details.

The  function is similar to , but it doesn't return a sorted copy of the collection. Instead it returns a list of indices that could be applied to the collection to produce a sorted version:

julia> r = rand(100:110, 10) 10-element Array{Int64,1}: 103 102  110  108  108  108  104  109  106  106

julia> sortperm(r) 10-element Array{Int64,1}: 2  1   7   9  10   4   5   6   8   3

julia> r[sortperm(r)]  10-element Array{Int64,1}: 102 103  104  106  106  108  108  108  109  110

Sort by and comparisons
If you need more than the default  offers, use the   and   keywords and provide your own functions for processing and comparing elements during the sort.

sort by
The  function processes each element before comparison and provides the 'key' for the sort. A typical example is the task of sorting a list of numbers in string form into numerical order. Here's the list:

julia> r = ["1E10", "150", "25", "3", "1.5", "1E-10", "0.5", ".999"];

If you use the default sort, the numbers appear in the order in which the characters appear in Unicode/ASCII:

julia> sort(r) 8-element Array{ASCIIString,1}: ".999" "0.5"  "1.5"  "150"  "1E-10" "1E10" "25" "3"

with "1E-10" appearing after "0.999".

To sort the numbers by their value, pass the  function (from the Meta package) to  :

julia> sort(r, by = x -> Meta.parse(x)) 8-element Array{String,1}: "1E-10" "0.5"   ".999"   "1.5"    "3"      "25"     "150"    "1E10"

The strings are sorted 'by' their value. Notice that the  function you supply produces the numerical sort key, but the original string elements appear in the final result.

Anonymous functions can be useful when sorting arrays. Here's a 10 rows by 2 columns array of tuples:

julia> table = collect(enumerate(rand(1:100, 10))) 10-element Array{(Int64,Int64),1}: (1,86) (2,25)  (3,3)   (4,97)  (5,89)  (6,58)  (7,27)  (8,93)  (9,98)  (10,12)

You can sort this array by the second element of each tuple, not the first, by supplying an anonymous function to  that points to the second element of each. The anonymous function says, given an object  to sort, sort by the second element of  :

julia> sort(table, by = x -> x[2]) 10-element Array{(Int64,Int64),1}: (3,3)  (10,12) (2,25)  (7,27)  (6,58)  (1,86)  (5,89)  (8,93)  (4,97)  (9,98)

Sorting by multiple columns
You can supply a tuple of "column" identifiers in the  function, if you want to sort by more than one column.

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

julia> sort(a, by = col -> (col[1], col[2], col[3])) 8-element Array{Array{Int64,1},1}: [1,1,1,8] [1,1,2,7]  [1,2,1,6]  [1,2,2,5]  [2,1,1,4]  [2,1,2,2]  [2,2,1,3]  [2,2,2,1]

This sorts the array first by column 1, then by column 2, then by column 3.

Redefining 'less than'
By default, sorting uses the built-in  function when comparing elements. In a sorted array, the first element is less than the second.

You can change this behaviour by passing a different function to the  keyword. This function should compare two elements and return true if they're sorted, i.e. if the first element is 'less than' the second, using some definition of 'less than'. The sorting process compares pairs of elements repeatedly until every element of the array is in the right place.

For example, suppose you want to sort an array of words according to the number of vowels in each word; i.e. the more vowels a word has, the earlier in the sorted results it occurs. For example, the word "orange" will be considered to be "less than" the word "lemon", because it has more vowels.

First we'll need a function that counts vowels:

Now you can pass an anonymous function to  that compares the vowel count of two elements using this function and then returns the element with a higher count in each case:

The result is that the word with the most vowels appears first:

The  function also lets you specify a reverse sort - after the   and   functions (if used) have done their work, a true value passed to   reverses the result.

Sorting 2-D arrays
In Julia 1.0, you can sort multidimensional arrays with.

Here's a simple array of nine strings (you can also use numbers, symbols, functions, or anything that can be compared):

julia> table = ["F" "B" "I"; "A" "D" "G"; "H" "C" "E"] 3×3 Array{String,2}: "F" "B"  "I" "A" "D"  "G" "H" "C"  "E"

You supply a number or a tuple to the  ("dimensions") keyword that indicates what you want to sort. To sort the table so that the first column is sorted, use :

julia> sortslices(table, dims=1) 3×3 Array{String,2}: "A" "D"  "G" "F" "B"  "I" "H" "C"  "E"

Note that  returns a new array. The first column is in alphabetical order.

Use  to sort the table so that the first row is sorted:

julia>> sortslices(table, dims=2) 3×3 Array{String,2}: "B" "F"  "I" "D" "A"  "G" "C" "H"  "E"

Now the first row is in alphabetical order.

If you want to sort by something other than the first item, pass a function to. So, to sort rows so that the middle column is in alphabetical order, use:

julia> sortslices(table, dims=1, by = x -> x[2]) 3×3 Array{String,2}: "F" "B"  "I" "H" "C"  "E" "A" "D"  "G"

has most of the options that you'll find in, and more besides. You can reverse the order with, change the comparator with  , and so on.

Tuples
A tuple is an ordered sequence of elements, like an array. A tuple is represented by parentheses and commas, rather than the square brackets used by arrays. Tuples are mostly good for small fixed-length collections — they're used everywhere in Julia, for example, as argument lists and for returning multiple values from functions.

The important difference between arrays and tuples is that tuples are immutable. Other than that, tuples work in much the same way as arrays, and many array functions can be used on tuples too:

julia> t = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) (1,2,3,4,5,6,7,8,9,10)

julia> t (1,2,3,4,5,6,7,8,9,10)

julia> t[6:end] (6,7,8,9,10)

You can have two-dimensional tuples:

julia> t = ((1, 2), (3, 4)) ((1,2),(3,4))

julia> t[1] (1,2)

julia> t[1][2] 2

But you can't change a tuple:

julia> t[1] = 0 LoadError: MethodError: no method matching set index!...

And, because you can't modify tuples, you can't use any of the functions like  that you use with arrays:

julia> a = [1,2,3]; julia> push!(a,4) 4-element Array{Int64,1}: 1 2 3 4

julia> t = (1,2,3); julia> push!(t,4) LoadError: MethodError: no method matching push!

Named tuples
A named tuple is like a combination of a tuple and a dictionary. Like a tuple, a named tuple is ordered and immutable, and enclosed in parentheses; like a dictionary, each element has a unique key that can be used to access it.

You can create a named tuple by providing keys and values directly:

julia> shape1 = (corner1 = (1, 1), corner2 = (-1, -1), center = (0, 0)) (corner1 = (1, 1), corner2 = (-1, -1), center = (0, 0))

To access the values, use the familiar dot syntax:

julia> shape1.corner1 (1, 1) julia> shape1.center (0, 0) julia> (shape1.corner1, shape1.corner2) ((1, 1), (-1, -1))

You can access all the values (destructuring) as with ordinary tuples:

julia> c1, c2, centerp = shape1; julia> c1 (1, 1) julia> c2 (-1, -1)

or just some of them:

julia> c1, c2 = shape1; julia> c1 (1, 1)

julia> c2 (-1, -1)

Elements can be the same type, or different types, but the keys will always be variable names.

You can iterate over a named tuple:

julia> for i in shape1  @show i end i = (1, 1) i = (-1, -1) i = (0, 0) julia> for i in shape1    println(first(i)) end 1 -1 0

Another way to create a named tuple is to provide the keys and values in separate tuples:

julia> ks = (:corner1, :corner2) (:corner1, :corner2) julia> vs = ((10, 10), (20, 20)) ((10, 10), (20, 20)) julia> shape2 = NamedTuple{ks}(vs) (corner1 = (10, 10), corner2 = (20, 20)) julia>shape2.corner1 (10, 10) julia> shape2.corner2 (20, 20)

You can combine two named tuples to make a new one:

julia> colors = (top = "red", bottom = "green") (top = "red", bottom = "green") julia> merge(shape2, colors) (corner1 = (10, 10), corner2 = (20, 20), top = "red", bottom = "green")

You can use existing variables for keys:

julia> d = :density; julia> (corner1 = (10, 10), corner2 = (20, 20), d => 0.99)

(corner1 = (10, 10), corner2 = (20, 20), density = 0.99)

Making single value Named Tuples requires a strategically-placed comma:

julia> shape3 = (corner1 = (1, 1),) (corner1 = (1, 1),)

julia> typeof(shape3) NamedTuple{(:corner1,),Tuple{Tuple{Int64,Int64}}}

If you forget it, you'll see this:

julia> (corner1 = (1, 1)) (1, 1) julia> typeof(corner1) Tuple{Int64,Int64}

You can make new named tuples by combining named tuples together.

julia> shape3 = merge(shape2, colors) (corner1 = (10, 10), corner2 = (20, 20), top = "red", bottom = "green") Use a comma after a single element named tuple:

julia> merge(shape2, (top = "green",)) (corner1 = (10, 10), corner2 = (20, 20), top = "green")

because without the comma, the tuple will be interpreted as a parenthesized keyword argument to.

To iterate over the "keys", use the  and   functions:

julia> fieldnames(typeof(shape3)) (:corner1, :corner2, :top, :bottom)

so you can do:

julia> for key in fieldnames(typeof(shape3))    @show getindex(shape3, key) end getindex(shape3, key) = (10, 10) getindex(shape3, key) = (20, 20) getindex(shape3, key) = "red" getindex(shape3, key) = "green"

Merging two tuples is done intelligently. For example, if you have this named tuple:

julia> shape3 (corner1 = (10, 10), corner2 = (20, 20), top = "red", bottom = "green")

and you want to add a center point and change the top color:

julia> merge(shape3, (center = (0, 0), top="green")) (corner1 = (10, 10), corner2 = (20, 20), top = "green", bottom = "green", center = (0, 0))

the new value is inserted, and the existing value is changed.

Using named tuples as keyword arguments
A named tuple is a convenient way to pass a group of keyword arguments to a function. Here's a function that accepts three keyword arguments:

function f(x, y, z; a=10, b=20, c=30) println("x = $x, y = $y, z = $z; a = $a, b = $b, c = $c") end

You can define a named tuple that contains the names and values for one or more keywords:

options = (b = 200, c = 300)

To pass the named tuple to the function, use the  when you call the function:

f(1, 2, 3; options...) x = 1, y = 2, z = 3; a = 10, b = 200, c = 300

If you specify a keyword and value, it can be overridden by a later definition:

f(1, 2, 3; b = 1000_000, options...) x = 1, y = 2, z = 3; a = 1000, b = 200, c = 300

f(1, 2, 3; options..., b= 1000_000) x = 1, y = 2, z = 3; a = 10, b = 1000000, c = 300