Julia is an advanced programming language which claims to have the performance of “C” and the ease of “Python”. This guide summarizes my impressions of Julia.
- Variables
- Control Flow
- Functions
- File IO
- Packages
- Unit Testing
Variables
The programming is loosely typed, meaning that variables vary in the type of information they store, and therefore are late interpreted. This is powerful but also less efficient. As a result, it is recommended to maintain efficient Julia code, that when a variable is defined and declared, that the programmer manually attempt to ensure that a variable’s data type not change.
a=1
b="some string"
c=3.1415
Note: Avoid the following
a=1
b="asda"
a=b
Data Types
typeof(true) # Bool
typeof(1) # Int64
typeof("some string") # String
typeof(3.1415) # Float64
typeof(3//2) # Rational{Int64}
typeof(Complex(4,2)) # Complex{Int64}
- See Arrays and Vectors
- See Dictionaries
- See Regex
- See Tuples
Comparison
a=1
b=2
a==1 # true - Equality
a==a # true
a==b # false
a!=b # true - Inequality
a<b # true - Less than
a>b # false - Greater than
a<=b # true - Less than or equal
a>=b # false - Greater than or equal
Type Conversion
convert(Float64, 4) # Ok. 4.0
convert(Int64, 3.1415) # ERROR: InexactError: Int64(3.1415)
string("a",1,true) # "a1true"
Numerical Variables
a=3
b=2
addition=a+b # 5
subtraction=a-b # 1
division=a/b # 1.5
multiplication=a*b # 6
power=a^b # 9
modulus=a%b # 1
rational=a//b # 3//2 I.e. stored as numerator and denominator for precision
String Variables
a="some string"
String Comparison
"4" > "5" # false
"exact" == "exact" # true
"exact" == "inexact" # false
String Interpolation
value = 3.1415 # 3.1415
"$value" # "3.1415"
"1 + 2 = $(1 + 2)" # "1 + 2 = 3"
String functions
# Case
uppercase("abc DEF gHI JkL") # "ABC DEF GHI JKL"
lowercase("abc DEF gHI JkL") # "abc def ghi jkl"
titlecase("abc DEF gHI JkL") # "Abc Def Ghi Jkl"
# Search
occursin("world", "hello world") # true
occursin("earth", "hello world") # false
findfirst("an","banana") # 2:3
findlast("an","banana") # 4:5
findfirst('a',"banana") # 2
findlast('a',"banana") # 6
repeat
repeat("rubarb",3) # "rubarbrubarbrubarb"
"rubarb"^3 # "rubarbrubarbrubarb"
Arrays
persons = ["Alice", "Bob", "Carla", "Daniel"]
Array Slicing
a = [1,2,3,4,5,6]
b = a[2:5] # 2,3,4,5
Array Memory Access
The keyword copy
is used to clone an array, safetly protecting an array from modification when used as an argument
# Memory Access
a=[1,2,3]
b=a # Unsafe array assignment
b[2] = 42
print(a) # [1, 42, 3]
a=[1,2,3]
b=copy(a) # Safe clone of array
b[2] = 42
print(a) # [1, 2, 3]
Array Comprehension
[i for i in 1:10] # Standard comprehension
[i+j for i in 1:10 for j in 1:5] # Nested comprehension
Multi Dimensional Arrays
# Operators with special names
[1 2 3] #hcat - ie. a Row of data
[1;2;3] #vcat - ie. a Column of data
A = [1 2;3 4;5 6] #hvcat - ie. A Matrix, an array of rows and columns
A' #adjoint - the Adjoint (inverted) matrix of A
A[1] # getindex
A[1] = 7 # setindex
A.n # getproperty
# Multi-Dimension Arrays
table = zeros(2,3,4)
for k in 1:4
for j in 1:3
for i in 1:2
table[i,j,k] = i*j*k
end
end
end
table
Matrix reshaping
mat1 = reshape([i for i in 1:16],4,4)
mat2 = mat1[2:3, 2:3] # Submatrix
mat1' # Adjunct
mat3 = reshape(mat1, 2,8)
Vectors
Vectors are just another name used for Arrays, typically where they have mixed data types
c=[1,2,3.6,"Sam"]
c[1] # 1
c[3:4] # 3.6, "Sam"
c[3:-1] # Any
Dictionaries
Dict("A"=>1,"B"=>2,"C"=>3) # Dict{String, Int64} with 3 entries:
# "B" => 2
# "A" => 1
# "C" => 3
Dict("A"=>1,"B"=>2,"C"=>3)["A"] # 1 - Fetch
Dict("A"=>1,"B"=>2,"C"=>3)["B"] # 2 - Fetch
Dict("A"=>1,"B"=>2,"C"=>3)["D"] # ERROR: KeyError: key "D" not found
Add key value pair
a = Dict("A"=>1,"B"=>2,"C"=>3)
a["D"] = 5 # Adds the values 5 with key "D"
a # Dict{String, Int64} with 4 entries:
# "B" => 2
# "A" => 1
# "C" => 3
# "D" => 5
Nesting Dictionaries
person1 = Dict("Name" => "Aurelio", "Phone" => 123456789, "Shoe-size" => 40)
person2 = Dict("Name" => "Elena", "Phone" => 123456789, "Shoe-size" => 36)
addressBook = Dict("Aurelio" => person1, "Elena" => person2)
addressBook["Elena"]["Phone"]
Tuples
Tuples a flexible type, often used to return multiple values from a function.
d = (1,2,3) # (1, 2, 3)
e = 1, 2, 3 # (1, 2, 3)
d[1] # 1
Tuple Packing
Packs the values 1, 2 and 3 into a tuple
a=(1,2,3)
Tuple Unpacking
Unpacks the values 1 into a, 2 into b, 3 into c
a, b, c = (1,2,3)
a # 1
b # 2
c # 3
Auto unpacking
function auto_unpack(a,b,c)
print("$a,$b,$c")
end
# Functions unpack automatically by appending ...
auto_unpack(tuple1...)
# For example
auto_unpack(("a","b","c")...) # a,b,c
Named Tuples
# Named tuples
a = (smith = 4, jones=5)
a[:jones] # 5
Regex
re = r"^\s*(?:#|$)" # Declaration
typeof(re) # Regex
Regex Searching
occursin returns a Bool value, if pattern is found or not
occursin(r"^\s*(?:#|$)", "not a comment") # false
occursin(r"^\s*(?:#|$)", "# a comment") # true
match returns a RegexMatch object, if a match is found
match(r"^\s*(?:#|$)", "not a comment") # <no value>
match(r"^\s*(?:#|$)", "# a comment") # RegexMatch("#")
Using a match
m = match(r"^\s*(?:#|$)", line)
if m === nothing
println("not a comment")
else
println("blank or comment")
end
Control Flow
If Else
if a > b
print('yes')
else
print('no')
end
For Loop
for i in 1:10
print(i)
end
Use of break
keyword, is similar to C#, terminating the loop
for i in 1:100
if i>10
break
else
println(i^2)
end
end
Use of continue
keyword is similar to C#, skipping to next loop iteration
for i in 1:30
if i % 3 == 0
continue
else
println(i)
end
end
While Loop
i=0
while(i<30)
println(i)
i += 1
end
Functions
Standard Functions
If keyword return
is not provided, the last calculation is assumed to be returned.
function simple(a,b)
a+b
end
simple(1,2) # 3
Inline Functions
g(x,y) = x+ y
g(1,2) # 3
Function as a Variable
g(x,y) = x+ y
g(1,2) # 3
h = g
h(4,5) # 9
Return Nothing
Returning keyword nothing
ensures that the function returns no value
function n(x,y)
print("Sum = $(x + y)")
return nothing
end
n(1,2) # Sum = 3
Operators are functions
1 + 2 + 3 # 6
+(1, 2, 3) # 6
p = + # + (generic function with 190 methods)
p(1,2,3) # 6
Broadcasting
Array Broadcasting
a = [1,2,3] # is a column vector
b = [4,5,6] # is a column vector
a * b # ERROR: MethodError: no method matching *(::Vector{Int64}, ::Vector{Int64})
c = [4 5 6] # is a row vector
a * c # 3-element Vector{Int64}:
# 3
# 6
# 9
c * a # 3-element Vector{Int64}:
# 3
# 6
# 9
d = reshape([1,2,3,4,5,6,7,8,9],3,3)
d * a # 3-element Vector{Int64}:
# 30
# 36
# 42
c * d # 3×3 Matrix{Int64}:
# 3 12 21
# 6 15 24
# 9 18 27
a * d # Fails
Special matrix operator .* ensures that rows and columns are correctly transposed before multiplication
a .* c
a * c
c .* a
a .* d # Does not fail due to broadcasting
Function Broadcasting
# Broadcasts the single value function Sin over the array
sin.([1,2,3]) # 3-element Vector{Float64}:
# 0.8414709848078965
# 0.9092974268256817
# 0.1411200080598672
Any method which takes a single argument can be used to broadcast over an array
function my_function(x)
collect(1:x)
end
my_function(6) # 6-element Vector{Int64}:
# 1
# 2
# 3
# 4
# 5
# 6
my_function(6)' # 1 2 3 4 5 6
# Broadcast function
my_function.([6 7 8]) # [1, 2, 3, 4, 5, 6] [1, 2, 3, 4, 5, 6, 7] [1, 2, 3, 4, 5, 6, 7, 8]
# Adjunct of broadcast function
my_function.([6 7 8])' # 3×1 adjoint(::Matrix{Vector{Int64}}) with eltype LinearAlgebra.Adjoint{Int64, Vector{Int64}}:
# [1 2 … 5 6]
# [1 2 … 6 7]
# [1 2 … 7 8]
File IO
Reading a File
open("war_and_peace.txt") do f
# line_number
line = 0
# read till end of file
while ! eof(f)
# read a new / next line for every iteration
s = readline(f)
line += 1
println("$line . $s")
end
end
Packages
Julia uses Packages
to encapsulate a collection of capabilities as a deployable and reusable asset.
The following example uses the Plots
package to draw a chart, of 10 random numbers.
Before the package can be used however, the local Package collection needs to be updated to ensure that the Plots
package can be accessed. The Pkg
package is a standard package which provides runtime access and management of packages on a system.
using Pkg
Pkg.add("Plots")
using Plots
x = 1:10; y = rand(10); # These are the plotting data
plot(x,y, label="my label")
Unit Testing
An example of very basic unit testing
using Test
@test true # <silently passes>
@test false # Test Failed at c:\...\unitTesting.jl:4
Here’s an example of a test which fails (intentionally)
using Test
function sum(a,b)
a - b # obvious bug here
end
@test sum(0,0) == 0 # Passes
@test sum(1,0) == 1 # Passes
@test sum(0,1) == 1 # Fails here
@test sum(1,1) == 2 # Not tested
# Test Failed at c:\...\unitTesting.jl:9
# Expression: sum(0, 1) == 1
# Evaluated: -1 == 1
# ERROR: LoadError: There was an error during testing
# in expression starting at c:\...\unitTesting.jl:9
Testing with a test set, results in all internal tests being run, regardless of previous results
using Test
function sum(a,b)
@debug "Testing sum($a,$b)"
a - b # obvious bug here
end
@testset "sum" begin
@test sum(0,0) == 0 # Passes
@test sum(1,0) == 1 # Passes
@test sum(0,1) == 1 # Fails here
@test sum(1,1) == 2 # Not tested
@test_skip sum(1,2) == 5 # Not executed
@test_broken sum(1,3) == 5 # Marked as a pass, but known to fail
@test_logs (:info,"Testing sum(0,0)") sum(0,0) == 0 # Passes, checking the logging info messages
end
# [ Info: Testing sum(0,0)
# [ Info: Testing sum(1,0)
# [ Info: Testing sum(0,1)
# sum: Test Failed at c:\...\unitTesting.jl:11
# Expression: sum(0, 1) == 1
# Evaluated: -1 == 1
# Stacktrace:
# [1] macro expansion
# @ c:\...\unitTesting.jl:11 [inlined]
# [2] macro expansion
# @ C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\Test\src\Test.jl:1151 [inlined]
# [3] top-level scope
# @ c:\...\unitTesting.jl:9
# [ Info: Testing sum(1,1)
# sum: Test Failed at c:\...\unitTesting.jl:12
# Expression: sum(1, 1) == 2
# Evaluated: 0 == 2
# Stacktrace:
# [1] macro expansion
# @ c:\...\unitTesting.jl:12 [inlined]
# [2] macro expansion
# @ C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\Test\src\Test.jl:1151 [inlined]
# [3] top-level scope
# @ c:\...\unitTesting.jl:9
# [ Info: Testing sum(1,3)
# Test Summary: | Pass Fail Broken Total
# sum | 3 2 2 7
# ERROR: LoadError: Some tests did not pass: 3 passed, 2 failed, 0 errored, 2 broken.
# in expression starting at c:\...\unitTesting.jl:8