# Data structures

## Contents

# Data structures¶

## Arrays¶

Arrays are one of the most important data structures for economists. They are equivalent of vectors and matrices in `Matlab`

or `R`

.
Arrays are multi-dimensional objects containing numbers (or different objects).

A vector is a one-dimensional array. To get a row vector you use the following convention:

```
A = [1 2 3]
```

```
1×3 Matrix{Int64}:
1 2 3
```

You get column vectors by using `;`

as the separator of elements:

```
B = [1; 2; 3]
```

```
3-element Vector{Int64}:
1
2
3
```

All elements of arrays must be of the same type. In case of type incompatibility across elements, coercion is performed:

```
@show c = [1 π 2.3]
@show typeof(c) #It's Float64 despite the first element being an integer.
```

```
c = [1 π 2.3] = [1.0 3.141592653589793 2.3]
typeof(c) = Matrix{Float64}
```

```
Matrix{Float64} (alias for Array{Float64, 2})
```

```
X = [1 2 3;
3 4 5]
```

```
2×3 Matrix{Int64}:
1 2 3
3 4 5
```

It is a good practice to initialize arrays before assigning values to their elements.
To create an empty one-dimensional array with `K`

elements of type `TYPE`

you use `Array{TYPE}(undef, K)`

.
Below an illustrating example:

```
Array{Float64}(undef, 10)
```

```
10-element Vector{Float64}:
3.5e-323
8.4e-323
9.4e-323
1.1e-322
1.2e-322
1.24e-322
1.43e-322
1.5e-322
1.53e-322
5.0e-324
```

Argument `undef`

means that nothing particular is assigned to all elements.
Instead, existing values stored previously in the memory are assigned.

To create an array of dimensions \(K\times N\times S\times W\) you use
`Array{TYPE}(undef, K, N, S, W)`

.
Below an illustrating example:

```
Array{Int}(undef, 2, 3, 2, 2)
```

```
2×3×2×2 Array{Int64, 4}:
[:, :, 1, 1] =
1 3 5
2 4 6
[:, :, 2, 1] =
7 9 11
8 10 12
[:, :, 1, 2] =
13 15 17
14 16 18
[:, :, 2, 2] =
19 21 23
20 22 24
```

To get an array with all elements constant, you use command `fill`

:

```
A = fill(π^2, 4, 3)
```

```
4×3 Matrix{Float64}:
9.8696 9.8696 9.8696
9.8696 9.8696 9.8696
9.8696 9.8696 9.8696
9.8696 9.8696 9.8696
```

To get an object of the same size and data type, function `similar`

can be useful. Elements of the new objects will contain information previously allocated in the memory.

```
B = similar(A)
```

```
4×3 Matrix{Float64}:
5.0e-324 2.5e-323 4.4e-323
1.0e-323 3.0e-323 5.0e-323
1.5e-323 3.5e-323 5.4e-323
2.0e-323 4.0e-323 6.0e-323
```

Arrays with zero elements can be constructed with `zeros`

:

```
zeros(3,2)
```

```
3×2 Matrix{Float64}:
0.0 0.0
0.0 0.0
0.0 0.0
```

To get an identity square matrix of dimension \(K\) function `I`

from package `LinearAlgebra`

can be used:

```
using LinearAlgebra
I(5)
```

```
5×5 Diagonal{Bool, Vector{Bool}}:
1 ⋅ ⋅ ⋅ ⋅
⋅ 1 ⋅ ⋅ ⋅
⋅ ⋅ 1 ⋅ ⋅
⋅ ⋅ ⋅ 1 ⋅
⋅ ⋅ ⋅ ⋅ 1
```

### Simple array operations¶

Except square-bracket notations, accessing arrays in `Julia`

is almost one-to-one analogy to `Matlab`

:

```
A = [1 2 3 4 5;
6 7 5 9 12]
```

```
2×5 Matrix{Int64}:
1 2 3 4 5
6 7 5 9 12
```

```
size(A)
```

```
(2, 5)
```

```
A[1,:] #1st row
```

```
5-element Vector{Int64}:
1
2
3
4
5
```

```
A[:,1] #1st column
```

```
2-element Vector{Int64}:
1
6
```

```
A[:,[1,3]] #1st and 3rd column
```

```
2×2 Matrix{Int64}:
1 3
6 5
```

```
A[:,3:end] #from 3rd to the LAST columns
```

```
2×3 Matrix{Int64}:
3 4 5
5 9 12
```

```
A[1,3:end] #1st row and from 3rd to the last columns
```

```
3-element Vector{Int64}:
3
4
5
```

Note

What can be quite natural for users of such languages as `R`

, `Matlab`

, or `Fortran`

, array indexing in `Julia`

starts from \(1.\)
This means that you get the fist element of an array `X`

by calling `X[1]`

.
This is different from such languages as `Python`

, `C++`

, or `Java`

, where array indexing starts from \(0.\)
For instance, in Python the fist element of an array `X`

is obtained by running `X[0]`

.
There are arguments for and against both conventions, which very often leads to heated debates, comparable to the editor war.

Just like with scalars, arithmetic operations on arrays of *the same dimensions* work in an analogous way:

```
A = [1 2;3 4];
B = I(2);
```

```
A + B
```

```
2×2 Matrix{Int64}:
2 2
3 5
```

```
A*A
```

```
2×2 Matrix{Int64}:
7 10
15 22
```

```
A
```

```
2×2 Matrix{Int64}:
1 2
3 4
```

```
A' #transposition
```

```
2×2 adjoint(::Matrix{Int64}) with eltype Int64:
1 3
2 4
```

```
A^(-1) #invert matrix
```

```
2×2 Matrix{Float64}:
-2.0 1.0
1.5 -0.5
```

```
maximum(A) #notice that `max`` works in a bit different way than in Matlab!
```

```
4
```

```
A^(-1)*A
```

```
2×2 Matrix{Float64}:
1.0 0.0
2.22045e-16 1.0
```

```
kron(A,I(3))
```

```
6×6 Matrix{Int64}:
1 0 0 2 0 0
0 1 0 0 2 0
0 0 1 0 0 2
3 0 0 4 0 0
0 3 0 0 4 0
0 0 3 0 0 4
```

Nonetheless, if we try to add an object of incompatible dimensions (including scalars), we will get an error message, just like in an example below:

```
A + 1
```

```
MethodError: no method matching +(::Matrix{Int64}, ::Int64)
For element-wise addition, use broadcasting with dot syntax: array .+ scalar
Closest candidates are:
+(::Any, ::Any, ::Any, ::Any...) at operators.jl:560
+(::T, ::T) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8} at int.jl:87
+(::Rational, ::Integer) at rational.jl:288
...
Stacktrace:
[1] top-level scope
@ In[27]:1
[2] eval
@ ./boot.jl:360 [inlined]
[3] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)
@ Base ./loading.jl:1094
```

This can be perceived as a particularly bizzare and excessively formal thing.
That said, at the development stage there were reasons for this.
Furthermore, notice that in Mathematics this type of operations, \(\mathbb{A}+1\), in most cases is also forbidden.
One (extremely inefficient but didactically useful) solution to this problem is to increase the size of the smaller object by using `repeat`

.
This function constructs an array by repeating the input *array* a given number of times in each out of the provided dimension.

Thus, to compute \(\mathbb{A}+1,\) we have to increase the size of \(1\) in such a way that the new object fits the size of \(\mathbb{A}\).
As we remember the size of \(\mathbb{A}\) is \(2\times 2.\)
Just to double check, let’s use function `size`

.

```
size(A)
```

```
(2, 2)
```

Below you can find `repeat`

at play:

```
repeat([1], 3)
```

```
3-element Vector{Int64}:
1
1
1
```

```
repeat([1], 3, 2)
```

```
3×2 Matrix{Int64}:
1 1
1 1
1 1
```

```
repeat([1], 4, 3, 2)
```

```
4×3×2 Array{Int64, 3}:
[:, :, 1] =
1 1 1
1 1 1
1 1 1
1 1 1
[:, :, 2] =
1 1 1
1 1 1
1 1 1
1 1 1
```

```
repeat([1; 2], 2, 3) #input argument: column vector
```

```
4×3 Matrix{Int64}:
1 1 1
2 2 2
1 1 1
2 2 2
```

```
repeat([1 2], 2, 3) #input argument: row vector
```

```
2×6 Matrix{Int64}:
1 2 1 2 1 2
1 2 1 2 1 2
```

Consequently, we are in the position to compute \(\mathbb{A}+1:\)

```
A + repeat([1], 2, 2)
```

```
2×2 Matrix{Int64}:
2 3
4 5
```

An addition of two arrays of different sizes can be conducted analogously:

```
A + repeat([0; 1], 1, 2)
```

```
2×2 Matrix{Int64}:
1 2
4 5
```

*Don’t* do this in your daily workflow

A *much more recommended* and **efficient** way to operate on objects of different sizes is to use broadcasting or mapping.
I discuss it in more details in one of the further secions.

### Assignment operator (`=`

) and arrays: easy for Pythonistas, confusing for Matlabians¶

What can be quite confusing at first for people with the `Matlab`

background is how the assignment operator (`=`

) works with arrays in `Julia`

.
In `Matlab`

if we want to create a matrix `V1`

that is a copy of another matrix `V0`

it is enough to write:

```
V1=V0
```

Henceforth, there are two *separate* matrices in the memory, `V1`

and `V0`

.
Any changes in either of those will not affect the other one.
In `Julia`

this works in a very different way.
Exactly like in `Python`

, running `V1=V0`

will create a new *pointer* to the memory allocated for `V0`

.
Both objects, `V1`

and `V0`

, share the same information.
Consequently, any changes in the memory through accessing `V1`

will affect the data pointed by `V0`

, and vice versa.
Below you can find an illustration of this language feature.

```
@show V₀ = [1 2 3];
```

```
V₀ = [1 2 3] = [1 2 3]
```

```
@show V₁ = V₀;
```

```
V₁ = V₀ = [1 2 3]
```

Running `V₁ = V₀`

will create a new pointer to the memory associated with `V₀`

.
Now changes in either of those objects will affect both pointers:

```
@show V₁[1] = 420;
@show V₁;
@show V₀;
@show V₀[3] = 128;
@show V₁;
@show V₀;
```

```
V₁[1] = 420 = 420
V₁ = [420 2 128]
V₀ = [420 2 128]
V₀[3] = 128 = 128
V₁ = [420 2 128]
V₀ = [420 2 128]
```

This feature of `Julia`

can be especially confusing in iterative procedures with updating values, such as value function iterations.
In this case, trying to create a copy of one array but making rather a new pointer instead will result in meeting the convergence criterion immediately after the first iteration (*terrible sentence*).
Obviously, this will not be correct.

A remedy to this issue can be simply addressed by using `deepcopy`

, which creates a *new object in the memory* that contains the same information as the copied object.

```
@show V₀ = [1 2 3];
@show V₁ = deepcopy(V₀);
```

```
V₀ = [1 2 3] = [1 2 3]
V₁ = deepcopy(V₀) = [1 2 3]
```

Now changes in either of those objects *will not* affect values pointed by the other object:

```
@show V₁[1] = 420;
@show V₁;
@show V₀;
@show V₀[3] = 128;
@show V₁;
@show V₀;
```

```
V₁[1] = 420 = 420
V₁ = [420 2 3]
V₀ = [1 2 3]
V₀[3] = 128 = 128
V₁ = [420 2 3]
V₀ = [1 2 128]
```

An important thing that should be also stressed is that this feature works only in the presence of assignments without additional operations.
If, for instance, code `V₁ = 2*V₀`

involves two operations: (1) multiplication `*(2,V₀)`

; and (2) making pointer `V₁`

to memory containing *results* from computing `*(2,V₀)`

in the past.
This means that memory spaces pointed by `V₁`

and by `V₀`

are two different things.

```
@show V₀ = [1 2 3];
@show V₁ = 2*V₀;
```

```
V₀ = [1 2 3] = [1 2 3]
V₁ = 2V₀ = [2 4 6]
```

```
@show V₁[1] = 420;
@show V₁;
@show V₀;
@show V₀[3] = 128;
@show V₁;
@show V₀;
```

```
V₁[1] = 420 = 420
V₁ = [420 4 6]
V₀ = [1 2 3]
V₀[3] = 128 = 128
V₁ = [420 4 6]
V₀ = [1 2 128]
```

## Dictionaries¶

Dictionaries are very useful objects that are particularly useful in my daily workflow.
They contain different objects and data structures of those types can be very different.
Dictionaries are initialized with `Dict`

and the list of the elements take arguments in the form `"name_of_the_object" => object`

.
An illustration below:

```
my_first_dict = Dict("X" => 2,
"Y" => 1:10)
```

```
Dict{String, Any} with 2 entries:
"Y" => 1:10
"X" => 2
```

Alternatively you can use a bit different notation, which I personally prefer (and I am not sure why): `Dict([ ("name_of_the_object1", object1) ])`

.
For example, if we want to create an object containing all parameters of our model, dictionaries are good candidates for it:

```
params = Dict([
("β" , (1/1.04)^(1/12)),
("b" , [.55 0]) ,
("vec_states" , 1:2) ,
("π", [1:10 20:29])
])
```

```
Dict{String, Any} with 4 entries:
"b" => [0.55 0.0]
"π" => [1 20; 2 21; … ; 9 28; 10 29]
"vec_states" => 1:2
"β" => 0.996737
```

Accessing elements of dictionaries has some similarities with arrays. The main difference is that we have to use names in quotates instead of indices:

```
@show params["β"]
params["π"]
```

```
params["β"] = 0.9967369426185624
```

```
10×2 Matrix{Int64}:
1 20
2 21
3 22
4 23
5 24
6 25
7 26
8 27
9 28
10 29
```

We can normally work on objects inside dictionaries.
Suppose we want to increase values of all rows but the last one of the first column of array `π`

by one we can do it by:

```
params["π"][1:(end-1),1] .+= 1;
params["π"]
```

```
10×2 Matrix{Int64}:
2 20
3 21
4 22
5 23
6 24
7 25
8 26
9 27
10 28
10 29
```

We can also add new elements to existing dictionaries. It is super simple:

```
params["Σ"] = 12
```

```
12
```

Now in in `params`

there is a new object `Σ`

:

```
params
```

```
Dict{String, Any} with 5 entries:
"Σ" => 12
"b" => [0.55 0.0]
"π" => [2 20; 3 21; … ; 10 28; 10 29]
"vec_states" => 1:2
"β" => 0.996737
```

In my own workflow, dictionaries are super useful for putting all blocks of models into one object.
I create a dictionary `economy`

with all parameters, value functions, simulations inside.
Thanks to this during analyses I can explore different parametrizations, counterfactual calibrations and what not in a very organized way.

Get used to assignments in `Julia`

You have to remember the assignment operator `=`

with whole dictionaries works in a very similar way as with arrays, *i.e.* it refers to memory containing information rather than information itself.

```
equation_copy = equation;
println("Before assignment:")
@show equation["c"];
@show equation_copy["c"];
println("ASSIGNMENT: equation_copy[\"c\"] = 420")
equation_copy["c"] = 420;
println("After assignment:")
@show equation["c"];
@show equation_copy["c"];
```

```
Before assignment:
equation["c"] = π
equation_copy["c"] = π
ASSIGNMENT: equation_copy["c"] = 420
After assignment:
equation["c"] = 420
equation_copy["c"] = 420
```

### Too many repetitions of dictionary names? `@unpack`

should help!¶

Suppose that we have a dictionary `equation`

containing a range of argumnents \(\mathbf{x}=\left(1+\frac{(i-1)}{10}\right)_{i=1}^{100}\) and values of coefficients \((a=1,b=12,c=\pi)\) characterizing a certain quadratic equation \(ax^2 + bx +c.\)

Then, our dictionary will be of the following form:

```
equation = Dict([
("x" , collect(range(1, step=.1, length=100)) ),
("a", 1),
("b", 12),
("c", π)
])
```

```
Dict{String, Any} with 4 entries:
"c" => π
"x" => [1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9 … 10.0, 10.1, 10.2…
"b" => 12
"a" => 1
```

Now suppose we want to evaluate the function calibrated with \((a=1,b=12,c=\pi)\) at \(\mathbf{x}.\)

One way to do it is as follows:

```
equation["y"] = @. equation["a"]*equation["x"]^2 + equation["b"]*equation["x"] + equation["c"]
```

```
100-element Vector{Float64}:
16.141592653589793
17.551592653589793
18.981592653589793
20.431592653589796
21.90159265358979
23.391592653589793
24.9015926535898
26.431592653589792
27.981592653589797
29.55159265358979
31.141592653589793
32.751592653589796
34.38159265358979
⋮
216.78159265358983
219.95159265358978
223.14159265358978
226.35159265358976
229.58159265358978
232.8315926535898
236.10159265358982
239.39159265358978
242.70159265358978
246.03159265358974
249.38159265358982
252.7515926535898
```

The code works but it does not have the nicest look and might be difficult to change.
In this case, macro `@unpack`

from package `Parameters`

can be helpful in making the code more legible.
This macro has the following syntax: `@unpack object_1, object_2 = dictionary_1`

.
`@unpack`

extracts objects with names `object_1`

and `object_2`

from `dictionary_1`

and makes them available in the current local scope. `dictionary_1`

might have other objects inside but `@unpack`

extracts only those explicitly mentioned objects.
Below you can see how it works

```
@show a #object a is only defined in dictionary equation, so you cannot access it
```

```
UndefVarError: a not defined
Stacktrace:
[1] top-level scope
@ show.jl:955
[2] eval
@ ./boot.jl:360 [inlined]
[3] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)
@ Base ./loading.jl:1094
```

```
using Parameters
@unpack a, b, c, x = equation
@show a #now it works
```

```
a = 1
```

```
1
```

Now to evaluate our quadratic function at \(\mathbb{x}\) we can do it by:

```
equation["y"] = @. a*x^2 + b*x + c
```

```
100-element Vector{Float64}:
16.141592653589793
17.551592653589793
18.981592653589793
20.431592653589796
21.90159265358979
23.391592653589793
24.9015926535898
26.431592653589792
27.981592653589797
29.55159265358979
31.141592653589793
32.751592653589796
34.38159265358979
⋮
216.78159265358983
219.95159265358978
223.14159265358978
226.35159265358976
229.58159265358978
232.8315926535898
236.10159265358982
239.39159265358978
242.70159265358978
246.03159265358974
249.38159265358982
252.7515926535898
```

You have to remember that in `@unpack`

, the assignment (`=`

) operator works normally… for `Julia`

. This means that if `object_1`

is a scalar while `object_2`

is an array, working with those objects can be very different.
This topic was discussed in this section.

Below you can find an example illustrating those differences:

```
@show equation["a"];
@show a;
@show a += 1;
@show equation["a"]; # `a += 1;` didn't change the value of `equation["a"]`
@show a; # `a += 1;` changed the value of `a`
```

```
equation["a"] = 1
a = 1
a += 1 = 2
equation["a"] = 1
a = 2
```

```
2
```

```
@show equation["x"];
@show x;
@show x .+= 1;
@show equation["x"]; # `x .+= 1;` CHANGED the value of `equation["x"]`
@show x; # `x .+= 1;` changed the value of `x`
```

```
equation["x"] = [1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6.0, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7.0, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 9.0, 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0, 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9]
x = [1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6.0, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7.0, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 9.0, 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0, 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9]
x .+= 1 = [2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6.0, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7.0, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 9.0, 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0, 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 11.0, 11.1, 11.2, 11.3, 11.4, 11.5, 11.6, 11.7, 11.8, 11.9]
equation["x"] = [2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6.0, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7.0, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 9.0, 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0, 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 11.0, 11.1, 11.2, 11.3, 11.4, 11.5, 11.6, 11.7, 11.8, 11.9]
x = [2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6.0, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7.0, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 9.0, 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10.0, 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 11.0, 11.1, 11.2, 11.3, 11.4, 11.5, 11.6, 11.7, 11.8, 11.9]
```

```
100-element Vector{Float64}:
2.0
2.1
2.2
2.3
2.4
2.5
2.6
2.7
2.8
2.9
3.0
3.1
3.2
⋮
10.8
10.9
11.0
11.1
11.2
11.3
11.4
11.5
11.6
11.7
11.8
11.9
```

While `a+=1`

*did not* have impact on `equation["a"]`

, `x .+= 1`

affected `equation["x"]`

. It is important to remember this feature of the language.

## Ranges¶

Ranges are quite intuitive objects.
They collect elements from a certain range of values.
They can be created either by using `:`

operator (just like in `R`

and `Matlab`

) or by using `range`

function.
For instance, if we want to create a range from 5 through 120, we can use two options:

```
@show 5:120;
@show range(5, stop=120);
```

```
5:120 = 5:120
range(5, stop = 120) = 5:120
```

Notice that you are not allowed to use `range(5,120)`

because at least one of `length`

, `stop`

, or `step`

must be specified explicitely.

If we want, we can set the size step. Again, it can be done in two ways:

```
@show 5:.5:120;
@show range(5, stop=120, step=.5);
```

```
5:0.5:120 = 5.0:0.5:120.0
range(5, stop = 120, step = 0.5) = 5.0:0.5:120.0
```

You can perform normal arithmetic operations:

```
(1:5)*2
```

```
2:2:10
```

However, be careful about the order of operations.
Arithmetic operations have a higher priority in `Julia`

.
For `Matlab`

users that is the same, but it might be problematic for `R`

users, where the order is different.
In `Julia`

if you type `1:5+1`

, you will give you `1:6`

, while in `R`

you will get `2:6`

.

```
1:5+1
```

```
1:6
```

Another important difference between other languages and `Julia`

is the fact that arrays and ranges are not compatible with each other.
This means that arithmetic operations will give you an error message, even if objects are of the same size:

```
1:3 + [1; 2; 3]
```

```
MethodError: no method matching +(::Int64, ::Vector{Int64})
For element-wise addition, use broadcasting with dot syntax: scalar .+ array
Closest candidates are:
+(::Any, ::Any, ::Any, ::Any...) at operators.jl:560
+(::T, ::T) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8} at int.jl:87
+(::Union{Int16, Int32, Int64, Int8}, ::BigInt) at gmp.jl:534
...
Stacktrace:
[1] top-level scope
@ In[293]:1
[2] eval
@ ./boot.jl:360 [inlined]
[3] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)
@ Base ./loading.jl:1094
```

You can extract all element from a range and create an array by using `collect`

:

```
collect(1:3)
```

```
3-element Vector{Int64}:
1
2
3
```

In this case, arithmetic operations are allowed:

```
collect(1:3) + [1; 2; 3]
```

```
3-element Vector{Int64}:
2
4
6
```

## Sets¶

To be written