Author Archives: Steven Whitaker

Basic Data Structures Explained

By: Steven Whitaker

Re-posted from: https://glcs.hashnode.dev/basic-data-structures

Julia is a relatively new,free, and open-source programming language.It has a syntaxsimilar to that of other popular programming languagessuch as MATLAB and Python,but it boasts being able to achieve C-like speeds.

Julia provides several useful data structuresfor storing and manipulating data.Some of these data structures,like arrays and dictionaries,are ubiquitous in Julia codebecause of their usefulnessand wide applicability.Others, like sets,have more limited usesbut neverthelessstill are useful data structures.

In this post,we will learn aboutarrays, dictionaries, and setsin Julia.We will discuss how to construct themand describe various functionsfor working with and manipulating them.

This post assumes you already have Julia installed.If you haven’t yet,check out our earlierpost on how to install Julia.

Arrays

One of the most basic and ubiquitous data structuresis the array.Arrays are used for storing values,iterating through values,and even representing mathematical vectors and matrices.

The basic array type in Julia is Array{T,N},where T is the type of the elements in the array(or an abstract supertype of the elementsif not all elements are of the same type),and N is the number of array dimensions.For example,a list of strings would be of type Array{String,1},while a matrix of numbers would be of type Array{Float64,2}.

Constructing Arrays

There are various waysto construct arrays.One common wayis to construct an arraydirectly from the valuesit will contain:

julia> ["some", "strings"]2-element Vector{String}: "some" "strings"julia> [1 2; 3 4]2x2 Matrix{Int64}: 1  2 3  4

(Note that Vector{T} is equivalent to Array{T,1}and that Matrix{T} is equivalent to Array{T,2}.)

Example arrays

Another common wayto construct arraysis using array comprehensions.An array comprehensioncreates an arrayby looping through a collection of valuesand computing an array elementfor each value.For example,the following creates an arraycontaining the squaresof the first five natural numbers:

julia> [x^2 for x = 1:5]5-element Vector{Int64}:  1  4  9 16 25

Multidimensional comprehensions also exist:

julia> [(x - 2)^2 + (y - 3)^2 <= 1 for x = 1:3, y = 1:5]3x5 Matrix{Bool}: 0  0  1  0  0 0  1  1  1  0 0  0  1  0  0

We can also create uninitialized arrays,either by passing undef to the array constructoror by calling similar:

julia> Array{Int,1}(undef, 1)1-element Vector{Int64}: 6303840julia> similar([1.0, 2.0])2-element Vector{Float64}: 6.94291544947797e-310 6.94291610129443e-310

(Note that the seemingly random numbers abovecome from whatever bits happen to be setin the memory allocated for the arrays.)

To create an array of zeros,call zeros:

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

Inspecting Arrays

Information about an arraycan be obtained using various functions.

length gives the number of elementsin an array:

julia> length([1, 2, 3])3julia> length(zeros(2, 3))6

size(x) gives the size of x,while size(x, d) gives the sizeof the dth dimension:

julia> size([1, 2, 3])(3,)julia> size(zeros(2, 3))(2, 3)julia> size(zeros(2, 3), 2)3

ndims gives the number of dimensionsof an array:

julia> ndims(zeros(1, 2, 3, 4, 5, 6))6

And eltype gives the typeof the elements of an array:

julia> eltype(["two", "strings"])Stringjulia> eltype([2, "different types"])Any

Array Operations

Accessing array elementsis achieved using brackets:

julia> a = [10, 20, 30];julia> a[2]20

(Note that arrays use one-based indexingin Julia.)

A similar syntax is usedto modify the contents of an array:

julia> a[1] = 00julia> a3-element Vector{Int64}:  0 20 30

Use commas (,) to separate indexesfor different dimensions,and use a colon (:)to select all the valuesalong a dimension:

julia> m = [1 2; 3 4]2x2 Matrix{Int64}: 1  2 3  4julia> m[1,2]2julia> m[:,1]2-element Vector{Int64}: 1 3

Multiple indexes can be provided:

julia> a[[1, 3]]2-element Vector{Int64}:  0 30

To assign a single valueto multiple array locations,use broadcasting:

julia> a[2:3] .= 02-element view(::Vector{Int64}, 2:3) with eltype Int64: 0 0julia> a3-element Vector{Int64}: 0 0 0

Arrays are also iterable,meaning we can loop throughthe values of an array:

julia> words = ["this", "is", "a", "sentence"];julia> for w in words           println(w)       endthisisasentence

Arrays as Stacks/Queues/Dequeues

Julia also provides some functionsthat allow arrays to be usedin a similar wayas stacks, queues, and dequeues.For example,push!(array, x) inserts xat the end of an array,and pop!(array) removes the last elementof an array.Similarly,pushfirst! and popfirstact on the beginning of an array.

Ranges

Ranges are another useful type of array,often used for loopingand array indexing.

The simplest syntaxfor creating a rangeis a:b,which creates a rangethat starts at aand includes all valuesa + 1, a + 2, etc.,as long as a + n <= b.For example,1:5 contains 1, 2, 3, 4, and 5,while 1.0:2.5 contains 1.0 and 2.0.

A step size, s, can also be specified,as in a:s:b.In this case, the spacing between valuesin the rangeis s instead of 1.

To create a range of N pointsbetween a and b, inclusive,use range(a, b, N).

Unlike Arrays,ranges are immutable,meaning their elementscan’t be modified.If modifying an element of a rangeis necessary,it must first be convertedinto an Arrayby calling collect:

julia> r = 1:21:2julia> r[1] = 10ERROR: CanonicalIndexError: setindex! not defined for UnitRange{Int64}julia> r_arr = collect(r)2-element Vector{Int64}: 1 2julia> r_arr[1] = 10; r_arr2-element Vector{Int64}: 10  2

That concludes our discussion of arrays,so now let’s move on to dictionaries.

Dictionaries

Another very common data structureis the dictionary.A dictionary is a mappingfrom keys to values:give a dictionary a key,and it will returnthe value associated with that key(if present).

In Julia,dictionaries are of type Dict{K,V},where K is the type of the keys,and V is the type of the values.

Dictionaries are constructedby providing key-value pairs:

julia> d = Dict("key1" => 1, "key2" => 2, "key3" => 3)Dict{String, Int64} with 3 entries:  "key2" => 2  "key3" => 3  "key1" => 1

(Note that a => bcreates a Pair in Julia.)

Indexing a dictionaryuses the same syntaxas indexing an array,just using keysinstead of array indexes:

julia> d["key2"]2

Accessing a dictionary

Use haskey to checkfor the presence of a key:

julia> haskey(d, "key3")truejulia> haskey(d, "nope")false

Dictionaries can also be updated:

julia> d["key1"] = 99999999julia> d["newkey"] = -9999-9999julia> dDict{String, Int64} with 4 entries:  "key2"   => 2  "key3"   => 3  "key1"   => 9999  "newkey" => -9999

Use delete!(dict, key)to delete the mappingfor the given key,if present.

We can also iteratethrough the keys and/or valuesof a dictionary:

  • Iterating keys: for k in keys(dict)
  • Iterating values: for v in values(dict)
  • Iterating both: for (k, v) in dict

That wraps up our discussion of dictionaries,so now we will move on to sets.

Sets

A set is a collection of unique elements.In Julia,sets are of type Set{T},where T is the typeof the elements of the set.Sets are usefulfor their efficient set operations,such as membership testing,union, and intersect.

Create an empty set of Float64 values as follows:

julia> s = Set{Float64}()Set{Float64}()

Use push! to add valuesto the set,noticing that the set changesonly if the value does not already existin the set:

julia> push!(s, 1.0);julia> push!(s, 1.2);julia> push!(s, 3.14)Set{Float64} with 3 elements:  1.2  3.14  1.0julia> push!(s, 1.0)Set{Float64} with 3 elements:  1.2  3.14  1.0

Use union to take the unionof two sets:

julia> t = Set([1.0, 2.0])Set{Float64} with 2 elements:  2.0  1.0julia> r = s  t # type \cup<tab> to get the union symbolSet{Float64} with 4 elements:  1.2  2.0  3.14  1.0

(Note that s t == union(s, t).)

Use intersect to take the intersectionof two sets:

julia> r  t # type \cap<tab> to get the intersection symbolSet{Float64} with 2 elements:  2.0  1.0

(Note that s t == intersect(s, t).)

Finally,we can check if an elementbelongs to a setwith in:

julia> 1.0  r # type \in<tab> to get the "is an element of" symboltrue

(Note that and in are interchangeable here.)

And with that,we conclude our overviewof some important Julia data structures.

Summary

In this post,we learned about a few data structuresthat Julia provides:arrays, dictionaries, and sets.We learned how to construct themand how to work with and manipulate them.

What are the most useful data structuresyou have used?Let us know in the comments below!

Have a better understandingof Julia’s basic data structures?Move on to thenext post to learn about multiple dispatch,one of Julia’s most distinctive features!Or,feel free to take a lookat our other Julia tutorial posts!

Additional Links

Explore the Capabilities of Broadcasting in Julia Programming

By: Steven Whitaker

Re-posted from: https://blog.glcs.io/broadcasting

Julia is a relatively new,
free, and open-source programming language.
It has a syntax
similar to that of other popular programming languages
such as MATLAB and Python,
but it boasts being able to achieve C-like speeds.

Unlike other languages
that focus on technical computing,
Julia does not require users
to vectorize their code
(i.e., to have one version of a function
that operates on scalar values
and another version
that operates on arrays).
Instead,
Julia provides a built-in mechanism
for vectorizing functions:
broadcasting.

Broadcasting is useful in Julia
for several reasons,
including:

  • It allows functions
    that operate on scalar values
    (e.g., cos())
    to operate elementwise
    on an array of values,
    eliminating the need
    for specialized, vectorized versions
    of those functions.
  • It allows for more efficient memory allocation
    in certain situations.
    For example,
    suppose we have a function, func,
    and we want to compute
    func(1, 2) and func(1, 3).
    Instead of broadcasting
    on [1, 1] and [2, 3],
    we can broadcast
    on 1 and [2, 3],
    avoiding the memory allocation
    for [1, 1].

On top of that,
Julia provides a very convenient syntax
for broadcasting,
making it so anyone
can easily use broadcasting in their code.

In this post,
we will learn what broadcasting is,
and we will see several examples
of how to effectively use broadcasting.

This post assumes you already have Julia installed.
If you haven’t yet,
check out our earlier
post on how to install Julia.

What Is Broadcasting?

Broadcasting essentially is a method
for calling functions elementwise
while virtually copying inputs
so that all inputs have the same size.
(For example,
if two inputs to a broadcasted function f
are 1 and [1, 2, 3],
the first input is treated
as if it is [1, 1, 1]
but without actually allocating memory
for an array.
Then the function is applied
to each pair of inputs:
f(1, 1), f(1, 2), and f(1, 3).)

If that definition doesn’t make sense right now,
don’t worry,
the examples below will help illustrate.

The Dot Syntax

The first thing to know about broadcasting
is that it is very convenient to use.

All you need to do is add dots.

For example,
if you want to take the square root
of a collection of values,
just add a dot (.):

julia> sqrt.([1, 4, 9]) # Notice the dot after `sqrt`
3-element Vector{Float64}:
 1.0
 2.0
 3.0

Vectorizing Operators and Functions

As stated earlier,
Julia doesn’t require
vectorized versions of functions.
In fact,
many functions don’t even have methods
that take array inputs.
Take sqrt for example:

julia> sqrt([1, 4, 9]) # No dot after `sqrt`
ERROR: MethodError: no method matching sqrt(::Vector{Int64})

So, even though sqrt
doesn’t have a vectorized version
explicitly defined,
the dot syntax still allows
sqrt to be applied elementwise.
The same applies to other functions and operators:

julia> [1, 2, 3] ^ 3 # No dot
ERROR: MethodError: no method matching ^(::Vector{Int64}, ::Int64)

julia> [1, 2, 3] .^ 3 # With dot
3-element Vector{Int64}:
  1
  8
 27

julia> uppercase(["hello", "world"]) # No dot
ERROR: MethodError: no method matching uppercase(::Vector{String})

julia> uppercase.(["hello", "world"]) # With dot
2-element Vector{String}:
 "HELLO"
 "WORLD"

Vectorization

Vectorization even works
with user-defined functions:

julia> myfunc(x) = x * 2
myfunc (generic function with 1 method)

julia> myfunc.([1, 2])
2-element Vector{Int64}:
 2
 4

Note that some functions
do have methods
that operate on arrays,
so be careful when deciding
whether a function should apply elementwise.
Take cos as an example:

julia> A = [0 ; /2 /6];

julia> cos(A) # Matrix cosine, *not* elementwise cosine
2x2 Matrix{Float64}:
 -0.572989  -0.285823
 -0.142912  -0.620626

julia> cos.(A) # Add a dot for computing the cosine elementwise
2x2 Matrix{Float64}:
 1.0          -1.0
 6.12323e-17   0.866025

Broadcasting with Multiple Inputs

Broadcasting gets more interesting
when multiple inputs are involved.
Let’s use addition (+) as an example.

We can add a scalar to each element of an array:

julia> [1, 2, 3] .+ 10
3-element Vector{Int64}:
 11
 12
 13

julia> 10 .+ [1, 2, 3]
3-element Vector{Int64}:
 11
 12
 13

Scalar-vector broadcasting

We can also sum two arrays elementwise:

julia> [1, 2, 3] .+ [10, 20, 30]
3-element Vector{Int64}:
 11
 22
 33

Broadcasting even works with arrays
of different sizes.
The only requirement is that non-singleton dimensions
must match across inputs.

julia> [1 2 3; 4 5 6] .+ [10, 20] # Sizes: (2, 3) and (2,)
2x3 Matrix{Int64}:
 11  12  13
 24  25  26

julia> [1 2 3; 4 5 6] .+ [10 20] # Sizes: (2, 3) and (1, 2)
ERROR: DimensionMismatch: arrays could not be broadcast to a common size; got a dimension with lengths 3 and 2

julia> [1 2 3; 4 5 6] .+ [10 20 30] # Sizes: (2, 3) and (1, 3)
2x3 Matrix{Int64}:
 11  22  33
 14  25  36

In the first example
([1 2 3; 4 5 6] .+ [10, 20]),
the column vector [10, 20]
was added to each column
of the matrix,
while in the second working example
([1 2 3; 4 5 6] .+ [10 20 30]),
the row vector [10 20 30]
was added to each row
of the matrix.

Matrix-vector broadcasting

Matrix-row-vector broadcasting

Treating Inputs as Scalars

Sometimes,
it is useful
to broadcast over
only a subset of the inputs.
For example,
suppose we have a function
that scales an input matrix:

julia> myfunc2(X, a) = X * a
myfunc2 (generic function with 1 method)

Suppose we want to scale a given matrix
by several different scale factors.
The result should be an array of matrices,
one matrix for each scale factor applied.
We might try to use broadcasting:

julia> X = [1 2; 3 4]; a = [10, 20];

julia> myfunc2.(X, a)
2x2 Matrix{Int64}:
 10  20
 60  80

But the result is just one matrix!
We have one matrix because
we broadcasted over a and X,
not just a.
In this case,
we need to wrap X
in a single-element Tuple:

julia> myfunc2.((X,), a)
2-element Vector{Matrix{Int64}}:
 [10 20; 30 40]
 [20 40; 60 80]

Now we have the result we want:
an array where the first entry
is X scaled by a[1]
and the second entry
is X scaled by a[2].

So,
whenever you need to treat an input
as a scalar
for broadcasting purposes,
just wrap it in a Tuple.

Broadcasting with Dictionaries and Strings

Dictionaries and strings
may act differently than expected
in broadcasting,
so let’s clarify some things here.

First,
attempting to broadcast over a dictionary
will throw an error:

julia> d = Dict("key1" => "hello", "key2" => "world")
Dict{String, String} with 2 entries:
  "key2" => "world"
  "key1" => "hello"

julia> println.(d)
ERROR: ArgumentError: broadcasting over dictionaries and `NamedTuple`s is reserved

There are different solutions
depending on the context.
For example:

  • Treat the dictionary as a scalar:
    julia> println.((d,)); # Note that `d` is wrapped in a `Tuple`
    Dict("key2" => "world", "key1" => "hello")
    
  • Broadcast over the values explicitly:
    julia> println.(values(d));
    world
    hello
    

Regarding strings,
strings are treated as scalars,
not as collections of characters.
For example:

julia> string.("string", [1, 2])
2-element Vector{String}:
 "string1"
 "string2"

(The above would have errored
if strings were not treated as scalars,
because length("string") is 6,
whereas length([1, 2]) is 2.)

To broadcast over the characters
in a string,
use collect:

julia> string.(collect("string"), 1:6)
6-element Vector{String}:
 "s1"
 "t2"
 "r3"
 "i4"
 "n5"
 "g6"

Summary

In this post,
we learned what broadcasting is,
and we saw several examples
of how to effectively use broadcasting
to apply functions elementwise.

Have any further questions about broadcasting?
Feel free to ask them
in the comments below!

Does broadcasting make sense now?
Move on to the
next post to learn about Julia’s type system!
Or,
feel free to take a look
at our other Julia tutorial posts!

Additional Links

Explore the Capabilities of Broadcasting in Julia Programming

By: Steven Whitaker

Re-posted from: https://glcs.hashnode.dev/broadcasting

Julia is a relatively new,free, and open-source programming language.It has a syntaxsimilar to that of other popular programming languagessuch as MATLAB and Python,but it boasts being able to achieve C-like speeds.

Unlike other languagesthat focus on technical computing,Julia does not require usersto vectorize their code(i.e., to have one version of a functionthat operates on scalar valuesand another versionthat operates on arrays).Instead,Julia provides a built-in mechanismfor vectorizing functions:broadcasting.

Broadcasting is useful in Juliafor several reasons,including:

  • It allows functionsthat operate on scalar values(e.g., cos())to operate elementwiseon an array of values,eliminating the needfor specialized, vectorized versionsof those functions.
  • It allows for more efficient memory allocationin certain situations.For example,suppose we have a function, func,and we want to computefunc(1, 2) and func(1, 3).Instead of broadcastingon [1, 1] and [2, 3],we can broadcaston 1 and [2, 3],avoiding the memory allocationfor [1, 1].

On top of that,Julia provides a very convenient syntaxfor broadcasting,making it so anyonecan easily use broadcasting in their code.

In this post,we will learn what broadcasting is,and we will see several examplesof how to effectively use broadcasting.

This post assumes you already have Julia installed.If you haven’t yet,check out our earlierpost on how to install Julia.

What Is Broadcasting?

Broadcasting essentially is a methodfor calling functions elementwisewhile virtually copying inputsso that all inputs have the same size.(For example,if two inputs to a broadcasted function fare 1 and [1, 2, 3],the first input is treatedas if it is [1, 1, 1]but without actually allocating memoryfor an array.Then the function is appliedto each pair of inputs:f(1, 1), f(1, 2), and f(1, 3).)

If that definition doesn’t make sense right now,don’t worry,the examples below will help illustrate.

The Dot Syntax

The first thing to know about broadcastingis that it is very convenient to use.

All you need to do is add dots.

For example,if you want to take the square rootof a collection of values,just add a dot (.):

julia> sqrt.([1, 4, 9]) # Notice the dot after `sqrt`3-element Vector{Float64}: 1.0 2.0 3.0

Vectorizing Operators and Functions

As stated earlier,Julia doesn’t requirevectorized versions of functions.In fact,many functions don’t even have methodsthat take array inputs.Take sqrt for example:

julia> sqrt([1, 4, 9]) # No dot after `sqrt`ERROR: MethodError: no method matching sqrt(::Vector{Int64})

So, even though sqrtdoesn’t have a vectorized versionexplicitly defined,the dot syntax still allowssqrt to be applied elementwise.The same applies to other functions and operators:

julia> [1, 2, 3] ^ 3 # No dotERROR: MethodError: no method matching ^(::Vector{Int64}, ::Int64)julia> [1, 2, 3] .^ 3 # With dot3-element Vector{Int64}:  1  8 27julia> uppercase(["hello", "world"]) # No dotERROR: MethodError: no method matching uppercase(::Vector{String})julia> uppercase.(["hello", "world"]) # With dot2-element Vector{String}: "HELLO" "WORLD"

Vectorization

Vectorization even workswith user-defined functions:

julia> myfunc(x) = x * 2myfunc (generic function with 1 method)julia> myfunc.([1, 2])2-element Vector{Int64}: 2 4

Note that some functionsdo have methodsthat operate on arrays,so be careful when decidingwhether a function should apply elementwise.Take cos as an example:

julia> A = [0 ; /2 /6];julia> cos(A) # Matrix cosine, *not* elementwise cosine2x2 Matrix{Float64}: -0.572989  -0.285823 -0.142912  -0.620626julia> cos.(A) # Add a dot for computing the cosine elementwise2x2 Matrix{Float64}: 1.0          -1.0 6.12323e-17   0.866025

Broadcasting with Multiple Inputs

Broadcasting gets more interestingwhen multiple inputs are involved.Let’s use addition (+) as an example.

We can add a scalar to each element of an array:

julia> [1, 2, 3] .+ 103-element Vector{Int64}: 11 12 13julia> 10 .+ [1, 2, 3]3-element Vector{Int64}: 11 12 13

Scalar-vector broadcasting

We can also sum two arrays elementwise:

julia> [1, 2, 3] .+ [10, 20, 30]3-element Vector{Int64}: 11 22 33

Broadcasting even works with arraysof different sizes.The only requirement is that non-singleton dimensionsmust match across inputs.

julia> [1 2 3; 4 5 6] .+ [10, 20] # Sizes: (2, 3) and (2,)2x3 Matrix{Int64}: 11  12  13 24  25  26julia> [1 2 3; 4 5 6] .+ [10 20] # Sizes: (2, 3) and (1, 2)ERROR: DimensionMismatch: arrays could not be broadcast to a common size; got a dimension with lengths 3 and 2julia> [1 2 3; 4 5 6] .+ [10 20 30] # Sizes: (2, 3) and (1, 3)2x3 Matrix{Int64}: 11  22  33 14  25  36

In the first example([1 2 3; 4 5 6] .+ [10, 20]),the column vector [10, 20]was added to each columnof the matrix,while in the second working example([1 2 3; 4 5 6] .+ [10 20 30]),the row vector [10 20 30]was added to each rowof the matrix.

Matrix-vector broadcasting

Matrix-row-vector broadcasting

Treating Inputs as Scalars

Sometimes,it is usefulto broadcast overonly a subset of the inputs.For example,suppose we have a functionthat scales an input matrix:

julia> myfunc2(X, a) = X * amyfunc2 (generic function with 1 method)

Suppose we want to scale a given matrixby several different scale factors.The result should be an array of matrices,one matrix for each scale factor applied.We might try to use broadcasting:

julia> X = [1 2; 3 4]; a = [10, 20];julia> myfunc2.(X, a)2x2 Matrix{Int64}: 10  20 60  80

But the result is just one matrix!We have one matrix becausewe broadcasted over a and X,not just a.In this case,we need to wrap Xin a single-element Tuple:

julia> myfunc2.((X,), a)2-element Vector{Matrix{Int64}}: [10 20; 30 40] [20 40; 60 80]

Now we have the result we want:an array where the first entryis X scaled by a[1]and the second entryis X scaled by a[2].

So,whenever you need to treat an inputas a scalarfor broadcasting purposes,just wrap it in a Tuple.

Broadcasting with Dictionaries and Strings

Dictionaries and stringsmay act differently than expectedin broadcasting,so let’s clarify some things here.

First,attempting to broadcast over a dictionarywill throw an error:

julia> d = Dict("key1" => "hello", "key2" => "world")Dict{String, String} with 2 entries:  "key2" => "world"  "key1" => "hello"julia> println.(d)ERROR: ArgumentError: broadcasting over dictionaries and `NamedTuple`s is reserved

There are different solutionsdepending on the context.For example:

  • Treat the dictionary as a scalar:
    julia> println.((d,)); # Note that `d` is wrapped in a `Tuple`Dict("key2" => "world", "key1" => "hello")
  • Broadcast over the values explicitly:
    julia> println.(values(d));worldhello

Regarding strings,strings are treated as scalars,not as collections of characters.For example:

julia> string.("string", [1, 2])2-element Vector{String}: "string1" "string2"

(The above would have erroredif strings were not treated as scalars,because length("string") is 6,whereas length([1, 2]) is 2.)

To broadcast over the charactersin a string,use collect:

julia> string.(collect("string"), 1:6)6-element Vector{String}: "s1" "t2" "r3" "i4" "n5" "g6"

Summary

In this post,we learned what broadcasting is,and we saw several examplesof how to effectively use broadcastingto apply functions elementwise.

Have any further questions about broadcasting?Feel free to ask themin the comments below!

Does broadcasting make sense now?Move on to thenext post to learn about Julia’s type system!Or,feel free to take a lookat our other Julia tutorial posts!

Additional Links