01 JULIA1 - 3A: Primitive types, char and strings (9:37)
01 JULIA1 - 3B: One dimensional arrays (30:42)
01 JULIA1 - 3C: Multidimensional arrays (23:37)
01 JULIA1 - 3D: Tuples and named tuples (7:50)
01 JULIA1 - 3E: Dictionaries and sets (8:57)
01 JULIA1 - 3F: Date and times (19:11)
0103 Predefined types
Some stuff to set-up the environment..
julia> cd(@__DIR__)
julia> using Pkg
julia> Pkg.activate(".") # If using a Julia version different than 1.10 please uncomment and run the following line (reproductibility guarantee will hower be lost) # Pkg.resolve() # Pkg.instantiate() # run this if you didn't in Segment 01.01
Activating project at `~/work/SPMLJ/SPMLJ/buildedDoc/01_-_JULIA1_-_Basic_Julia_programming`
julia> using Random
julia> Random.seed!(123)
Random.TaskLocalRNG()
julia> using InteractiveUtils # loaded automatically when working... interactively
Primitive types
Primitive types have a fixed number of bits associated to them. Examples of them are Int64
, Float64
, Char
, UInt64
, UFloat64
, Int32
, Float32
,... Even primitive types can be custom defined. See the "custom types" segment !
Char and Strings - Char
, String
julia> a = "Hello World "
"Hello World "
julia> b = a[2]
'e': ASCII/Unicode U+0065 (category Ll: Letter, lowercase)
julia> typeof(b)
Char
julia> b = a[3:end]
"llo World "
julia> typeof(b) # a[2] = 'E' # error !
String
Information...
julia> ismutable(a) # long story.... https://github.com/JuliaLang/julia/issues/30210
true
julia> length(a)
12
julia> findfirst(isequal('o'), a)
5
julia> findnext(isequal('o'), a, 6)
8
julia> occursin("world",a)
false
julia> occursin(lowercase("world"),lowercase(a))
true
julia> using Unicode
julia> occursin(Unicode.normalize("world", casefold=true),Unicode.normalize(a, casefold=true))
true
julia> endswith(a,"ld ")
true
julia> startswith(a,"Mooo")
false
julia> occursin(r"H*.d ", a)
true
Modifications..
julia> lowercase(a)
"hello world "
julia> lowercasefirst(a)
"hello World "
julia> split(a, " ")
3-element Vector{SubString{String}}: "Hello" "World" ""
julia> replace(a,"World" => "Universe")
"Hello Universe "
julia> strip(a)
"Hello World"
Concatenation..
julia> a = "Hello"; b= "World"
"World"
julia> c = join([a,b]," ")
"Hello World"
julia> c = a*" "*b
"Hello World"
julia> c = string(a," ",b)
"Hello World"
julia> c = "$a $b" # interpolation # Conversion..
"Hello World"
julia> a = parse(Int64,"2012")
2012
julia> b = string(2019)
"2019"
Attention not to confuse the string
function with the String
type and the String()
constructor!
to know more...
julia> methodswith(String,supertypes=true); # where any argument is a String or any parent type (such e.g. AbstractString)
See also https://docs.julialang.org/en/v1/manual/strings/
Arrays - Array{T,N}
Array{T,NDims}
A parameteric type where the type of the content and the number of dimensions define the specific type
Vector{T}
is an alias for Array{T,1}
and Matrix{T}
is an alias for Array{T,2}
, but there isn't anything "special" for 1 or 2 dimensions compared to more dimensions
Vectors - Array{T,1}
One-dimensions arrays in julia are treated as column vector, and, depending on the inner type, they can be stored efficiently contiguously in memory. However they are NOT the same of a single column of a two dimensions array. A row vector is necessarily instead a single row of a 2 dimensions array.
julia> a = [1,2,3]
3-element Vector{Int64}: 1 2 3
julia> b = [1 ; 2 ; 3 ;;] # This syntax requires Julia >= 1.7
3×1 Matrix{Int64}: 1 2 3
julia> a == b
false
Initialisation
julia> a = [1,2,3]; #= or =# a = [1;2;3]
3-element Vector{Int64}: 1 2 3
julia> a = [1; 6:-2:2; 10] # notes: (a) the semicolon, (b) the range includes BOTH the extremes
5-element Vector{Int64}: 1 6 4 2 10
julia> a = [[1,2],[3,4]] # nested vectors. Each elements can have a different lenght, but rules of linear algebra doesn't apply
2-element Vector{Vector{Int64}}: [1, 2] [3, 4]
Don't confuse nested vectors with multi-dimensional arrays!
Empty (zero-elements) arrays:
julia> a = []
Any[]
julia> a = Int64[]
Int64[]
julia> a = [1,2,3]
3-element Vector{Int64}: 1 2 3
julia> b = [1,"pizza","beer"]
3-element Vector{Any}: 1 "pizza" "beer"
julia> a = Array{Int64,1}()
Int64[]
Watch out for the difference between a = Array{Int64,1}()
and a = Array{Int64,1}
julia> a = Vector{Int64}()
Int64[]
n-elements initialisation:
julia> n = 3
3
julia> T = Int64
Int64
julia> zeros(n) # zeros (Float64)
3-element Vector{Float64}: 0.0 0.0 0.0
julia> zeros(T,n) # zeros (casted as type T)
3-element Vector{Int64}: 0 0 0
julia> ones(n) # ones (Float64)
3-element Vector{Float64}: 1.0 1.0 1.0
julia> ones(T,n) # ones (casted of type T)
3-element Vector{Int64}: 1 1 1
julia> Array{T,1}(undef,n) # garbage
3-element Vector{Int64}: 140142704513200 140142709059264 0
julia> fill(2,3)
3-element Vector{Int64}: 2 2 2
Accessing Vectors
julia> a = [10,20,30,40,50,60,70,80,90]
9-element Vector{Int64}: 10 20 30 40 50 60 70 80 90
julia> a[1]
10
julia> a[end]
90
julia> a[[1; 6:-2:2; 8]] # indicised by a vector of positions
5-element Vector{Int64}: 10 60 40 20 80
Collecting iterators into vectors
julia> aRange = 3:2:7
3:2:7
julia> a = collect(aRange)
3-element Vector{Int64}: 3 5 7
julia> a = [3:2:7;] # alternative
3-element Vector{Int64}: 3 5 7
julia> typeof(aRange)
StepRange{Int64, Int64}
julia> typeof(aRange) <: AbstractArray # Everywhere an AbstractArray is expected, you can provide a range instead
true
Common operations with vectors
julia> a = [1,2,3]
3-element Vector{Int64}: 1 2 3
julia> reverse(a), a[end:-1:1] # Other way to revert an array
([3, 2, 1], [3, 2, 1])
julia> vcat([1,2,3],[4,5],6)
6-element Vector{Int64}: 1 2 3 4 5 6
julia> push!(a,4) # add as individual elements
4-element Vector{Int64}: 1 2 3 4
julia> append!(a,5) # add as many new elements
5-element Vector{Int64}: 1 2 3 4 5
By convention functions that modify one of their parameters (and usually this is the first one) are named with an exclamation mark at the end. Remember (most) unicode characters are valid in functions or variable names.
julia> push!([[1,2],[3,4,5]],[6,7])
3-element Vector{Vector{Int64}}: [1, 2] [3, 4, 5] [6, 7]
julia> append!([1,2,3,4,5],[6,7])
7-element Vector{Int64}: 1 2 3 4 5 6 7
julia> pop!(a)
5
julia> a
4-element Vector{Int64}: 1 2 3 4
julia> popfirst!(a)
1
julia> deleteat!(a,2)
2-element Vector{Int64}: 2 4
julia> pushfirst!([2,3],1)
3-element Vector{Int64}: 1 2 3
julia> a = [2,1,3,1]
4-element Vector{Int64}: 2 1 3 1
julia> sort(a) # also `sort!(a)``
4-element Vector{Int64}: 1 1 2 3
julia> unique(a) # also `unique!(a)`
3-element Vector{Int64}: 2 1 3
julia> in(1,a) # also available as operator: `if 2 in a [...] end`
true
julia> length(a) # number of elements contained in all the dimensions
4
julia> size(a),size(a,1) # number of elements by dimension
((4,), 4)
julia> minimum(a)
1
julia> min(a...)
1
"..." is called the splat operator and it is used to convert the elements in a vector into a tuple of separate elements in a function call, like the example above
julia> min(4,7,3)
3
julia> minimum([4,7,9])
4
julia> argmin([4,2,5,2])
2
julia> sum([1,2,3])
6
julia> cumsum([1,2,3])
3-element Vector{Int64}: 1 3 6
julia> empty!(a) # only for Vectors
Int64[]
julia> using Random
julia> shuffle([1,2,3]) # also shuffle!([1,2,3])
3-element Vector{Int64}: 1 3 2
julia> isempty(a)
true
julia> findall(x -> x == 1, [2,1,3,1]) # anonymous function returning an array of bools, findall then return the indexes
2-element Vector{Int64}: 2 4
julia> findfirst(x -> x == 1, [2,1,3,1])
2
julia> myComparitionWith1(i) = i==1
myComparitionWith1 (generic function with 1 method)
julia> findall(x -> myComparitionWith1(x), [2,1,3,1])
2-element Vector{Int64}: 2 4
julia> filter(i -> i > 2, [1,2,3,4])
2-element Vector{Int64}: 3 4
Delete [7,2,5] from an
1:10` array:
julia> data = [1:10;]
10-element Vector{Int64}: 1 2 3 4 5 6 7 8 9 10
julia> toDelete = [7,5,2]
3-element Vector{Int64}: 7 5 2
julia> deleteat!(data, findall(x -> x in toDelete, data))
7-element Vector{Int64}: 1 3 4 6 8 9 10
julia> for (i,value) in enumerate([10,20,30]) # iterator that returns an index/element tuple println("$i - $value") end
1 - 10 2 - 20 3 - 30
julia> names = ["Marc", "Anne"]
2-element Vector{String}: "Marc" "Anne"
julia> sex = ['M','F']
2-element Vector{Char}: 'M': ASCII/Unicode U+004D (category Lu: Letter, uppercase) 'F': ASCII/Unicode U+0046 (category Lu: Letter, uppercase)
julia> age = [25,20]
2-element Vector{Int64}: 25 20
julia> for zippedElements in zip(names,sex,age) # iterator that returns tuples made with one element per argument of zip println(zippedElements) end
("Marc", 'M', 25) ("Anne", 'F', 20)
Multidimensional arrays - Array{T,N}
Initialisation
julia> a = [[1,2,3] [4,5,6]] # By column, i.e. elements of the first column, elements of the second column, ...
3×2 Matrix{Int64}: 1 4 2 5 3 6
julia> a = [1 4; 2 5; 3 6] # By row, i.e. elements of the first row, elements of the second row, ... # Empty (zero-elements) arrays:
3×2 Matrix{Int64}: 1 4 2 5 3 6
julia> a = Array{Float64}(undef, 0, 0, 0) # using explicitly the constructor and explicitly giving zero for each wanted dimension
0×0×0 Array{Float64, 3}
n-elements initialisation:
julia> (T,n,m,g,j) = (Int64,1,2,3,'a')
(Int64, 1, 2, 3, 'a')
julia> a = zeros(n,m,g) # n,m,g-elements zeros array
1×2×3 Array{Float64, 3}: [:, :, 1] = 0.0 0.0 [:, :, 2] = 0.0 0.0 [:, :, 3] = 0.0 0.0
julia> a = ones(n,m,g) # n,m,g-elements ones array
1×2×3 Array{Float64, 3}: [:, :, 1] = 1.0 1.0 [:, :, 2] = 1.0 1.0 [:, :, 3] = 1.0 1.0
julia> a = Array{T,3}(undef,n,m,g) # n,m,g-elements array whose content is garbage
1×2×3 Array{Int64, 3}: [:, :, 1] = 140147676691024 140147676691024 [:, :, 2] = 140147676691024 140147676691024 [:, :, 3] = 140147676691024 140147676691024
julia> a = fill(j,n,m,g) # n,m,g-elements array of identical j elements
1×2×3 Array{Char, 3}: [:, :, 1] = 'a' 'a' [:, :, 2] = 'a' 'a' [:, :, 3] = 'a' 'a'
julia> a = rand(n,m,g) # n,m,g-elements array of of random numbers
1×2×3 Array{Float64, 3}: [:, :, 1] = 0.890879 0.190907 [:, :, 2] = 0.525662 0.390588 [:, :, 3] = 0.044818 0.933353
julia> a = [3x + 2y + z for x in 1:2, y in 2:3, z in 1:2] # from using list comprehension
2×2×2 Array{Int64, 3}: [:, :, 1] = 8 10 11 13 [:, :, 2] = 9 11 12 14
Accessing n-dimensional arrays
Access by indicating position
julia> a = [1 2 3 4; 5 6 7 8; 9 10 11 12]
3×4 Matrix{Int64}: 1 2 3 4 5 6 7 8 9 10 11 12
julia> a[2,1] # comma to separate the dimensions
5
Don't confuse a[i,j]
for selecting an element of a Matrix with a[i][j]
to select the inner component of a nested array
julia> a[1,2:3] # with a range on the second dimension
2-element Vector{Int64}: 2 3
julia> a[[1,3],1] # with a vector of positions in the first dimension
2-element Vector{Int64}: 1 9
julia> a[2,:] # with a full range (all values) in the second dimension, i.e. all columns value for row 2
4-element Vector{Int64}: 5 6 7 8
Note that when the data as only one element on a given dimension, julia reduces the dimensions automatically: the result of a[2,:]
is NOT a row vector (that is a one-row matrix) but a one dimensional array
Access by a mask (boolean selection)
julia> b = [true false true false; true true true false; true false true false]
3×4 Matrix{Bool}: 1 0 1 0 1 1 1 0 1 0 1 0
julia> a[b] # always flatted array returned (need eventually reshaping, see later)
7-element Vector{Int64}: 1 5 9 6 3 7 11
Funcionality related to dimensions
julia> size(a) # returns a tuple (i.e. an immutable list) with the sizes of the n dimensions
(3, 4)
julia> ndims(a) # return the number of dimensions of the array (e.g. `2` for a matrix)
2
julia> reshape(a, 2,3,2)
2×3×2 Array{Int64, 3}: [:, :, 1] = 1 9 6 5 2 10 [:, :, 2] = 3 11 8 7 4 12
julia> 2*3*2 == length(a)
true
julia> b = rand(2,1,3)
2×1×3 Array{Float64, 3}: [:, :, 1] = 0.5805599818745412 0.32723787925628356 [:, :, 2] = 0.5269959187969865 0.8362285750521512 [:, :, 3] = 0.04090613602769255 0.4652015053812224
julia> dropdims(b,dims=(2)) # remove the specified dimensions, provided that the specified dimension have only a single element
2×3 Matrix{Float64}: 0.58056 0.526996 0.0409061 0.327238 0.836229 0.465202
julia> permutedims(a) # "swap" the dimensions
4×3 Matrix{Int64}: 1 5 9 2 6 10 3 7 11 4 8 12
julia> reshape(a,4,3) # keep the column mayor order
4×3 Matrix{Int64}: 1 6 11 5 10 4 9 3 8 2 7 12
julia> for slice in eachslice(a,dims=1) println(slice) end
[1, 2, 3, 4] [5, 6, 7, 8] [9, 10, 11, 12]
julia> a = reshape(1:24, 3,4,2)
3×4×2 reshape(::UnitRange{Int64}, 3, 4, 2) with eltype Int64: [:, :, 1] = 1 4 7 10 2 5 8 11 3 6 9 12 [:, :, 2] = 13 16 19 22 14 17 20 23 15 18 21 24
julia> for slice in eachslice(a,dims=1) println(slice) end
[1 13; 4 16; 7 19; 10 22] [2 14; 5 17; 8 20; 11 23] [3 15; 6 18; 9 21; 12 24]
julia> a = [1 2;3 4; 5 6]
3×2 Matrix{Int64}: 1 2 3 4 5 6
julia> selectdim(a,1,3) # Select an hyperplane on dimension 1 (rows) at position 3. Returns a view
2-element view(::Matrix{Int64}, 3, :) with eltype Int64: 5 6
Flat to vector..
julia> a = [1 2; 3 4]
2×2 Matrix{Int64}: 1 2 3 4
julia> vec(a) # shadow copy (different view of the underlying data)
4-element Vector{Int64}: 1 3 2 4
julia> reshape(a,4) # shadow copy
4-element Vector{Int64}: 1 3 2 4
julia> a[:] # allocate, as all slice operations do
4-element Vector{Int64}: 1 3 2 4
Other functionality related to Arrays
julia> vcat([1 2; 3 4], [5 6; 7 8]) # works also for DataFrames
4×2 Matrix{Int64}: 1 2 3 4 5 6 7 8
julia> hcat([1,2,3],[4,5,6]) # works also for DataFrames
3×2 Matrix{Int64}: 1 4 2 5 3 6
julia> a = [1 2; 3 4]
2×2 Matrix{Int64}: 1 2 3 4
julia> b = similar(a) # garbage inside
2×2 Matrix{Int64}: 140145285662960 140145285663024 140145285662992 140145285663056
julia> cat(a,a,a,dims=3)
2×2×3 Array{Int64, 3}: [:, :, 1] = 1 2 3 4 [:, :, 2] = 1 2 3 4 [:, :, 3] = 1 2 3 4
Sort by column (field)
julia> a = [[3,2,1] [20,30,20] [1000,3000,2000] [300,100,200]]
3×4 Matrix{Int64}: 3 20 1000 300 2 30 3000 100 1 20 2000 200
julia> idx = sortperm(a[:,3], rev=true) # return the positions that sort the 3rd column
3-element Vector{Int64}: 2 3 1
julia> sortedMatrix = a[idx,:] # selected by using the sorted positions array on the row dimension
3×4 Matrix{Int64}: 2 30 3000 100 1 20 2000 200 3 20 1000 300
julia> sortslices(a, dims=2) # by cols, using the first row to sort
3×4 Matrix{Int64}: 3 20 300 1000 2 30 100 3000 1 20 200 2000
julia> sortslices(a, dims=1) # by rows, using the first column to sort
3×4 Matrix{Int64}: 1 20 2000 200 2 30 3000 100 3 20 1000 300
julia> sortslices(a, dims=1, by = x -> (x[2],x[4])) # by rows, using second and fourth columns
3×4 Matrix{Int64}: 1 20 2000 200 3 20 1000 300 2 30 3000 100
Basic linear algebra
julia> using LinearAlgebra
julia> a = [-1,2,3]
3-element Vector{Int64}: -1 2 3
julia> b = [4,5,6]
3-element Vector{Int64}: 4 5 6
julia> transpose(a)
1×3 transpose(::Vector{Int64}) with eltype Int64: -1 2 3
julia> a'
1×3 adjoint(::Vector{Int64}) with eltype Int64: -1 2 3
julia> norm(a) # l-2 by default
3.7416573867739413
julia> norm(a,1)
6.0
Vector products:
julia> dot(a,b) # dot, aka "inner" product
24
julia> a' * b == dot(a,b)
true
julia> cross(a,b) # cross product
3-element Vector{Int64}: -3 18 -13
julia> a .* b # element-wise product
3-element Vector{Int64}: -4 10 18
julia> a * b'
3×3 Matrix{Int64}: -4 -5 -6 8 10 12 12 15 18
julia> A = [1 2 3; 6 4 5; 7 8 9]
3×3 Matrix{Int64}: 1 2 3 6 4 5 7 8 9
julia> A^(-1) # inverse
3×3 Matrix{Float64}: -0.222222 0.333333 -0.111111 -1.05556 -0.666667 0.722222 1.11111 0.333333 -0.444444
julia> A^2
3×3 Matrix{Int64}: 34 34 40 65 68 83 118 118 142
julia> det(A) # determinant
18.000000000000004
julia> transpose(A)
3×3 transpose(::Matrix{Int64}) with eltype Int64: 1 6 7 2 4 8 3 5 9
julia> A'
3×3 adjoint(::Matrix{Int64}) with eltype Int64: 1 6 7 2 4 8 3 5 9
Be aware that transpose
works only for numerical types. When the matrix contains other types (e.g. strings), use permutedims
julia> diag(A)
3-element Vector{Int64}: 1 4 9
julia> I # operator that automatically scale to the context without actually building the matrix
LinearAlgebra.UniformScaling{Bool} true*I
julia> A*I
3×3 Matrix{Int64}: 1 2 3 6 4 5 7 8 9
julia> B = [1 2; 3 4]; B*I
2×2 Matrix{Int64}: 1 2 3 4
julia> (evalues, evectors) = eigen(A)
LinearAlgebra.Eigen{ComplexF64, ComplexF64, Matrix{ComplexF64}, Vector{ComplexF64}} values: 3-element Vector{ComplexF64}: -0.8056073109913213 - 0.7099395230053245im -0.8056073109913213 + 0.7099395230053245im 15.611214621982644 + 0.0im vectors: 3×3 Matrix{ComplexF64}: -0.267976-0.290703im -0.267976+0.290703im 0.239114+0.0im 0.777975-0.0im 0.777975+0.0im 0.485634+0.0im -0.426158+0.238381im -0.426158-0.238381im 0.840824+0.0im
Tuples - Tuple{T1,T2,...}
A "collection" similar to Array but:
- Immutable
- Can efficiently host heterogeneous types, as type information is stored for each individual element
- Linear algebra doesn't apply (use StaticArray.jl package for that)
Can be tought as anonymous (immutable) structures Used to unpack multiple values, e.g. to store on inddividual variables the output of functions with multiple return value
Initialisation
julia> t = (1,2.5,"a",3)
(1, 2.5, "a", 3)
julia> t = 1,2.5,"a",3
(1, 2.5, "a", 3)
julia> typeof(t)
Tuple{Int64, Float64, String, Int64}
Indexing
julia> t[1]
1
Conversion
julia> v = [1,2,3]
3-element Vector{Int64}: 1 2 3
julia> t = (v...,) # note the comma
(1, 2, 3)
julia> v2 = [t...]
3-element Vector{Int64}: 1 2 3
julia> v3 = [i[1] for i in t]
3-element Vector{Int64}: 1 2 3
julia> v4 = collect(t)
3-element Vector{Int64}: 1 2 3
julia> v == v2 == v3 == v4
true
Tuples with a variable number of same-type elements
While the tuple type normally include informations of the types of each elements, one by one, we may want to have a way to "summarise" this information by specifying that a certain number of elements, all of this type, are repeated. This is the task of the Vararg{T}
and Vararg{T,N}
arguments that must be specified as the last parameters of a Tuple
type. The former one allows for a variable number of elements, and the latter one specific an exact number of elements:
julia> typeof(("aaa",1,10)) <: Tuple{String,Vararg{Int}}
true
julia> typeof(("aaa",1,10)) <: Tuple{String,Vararg{Int,2}}
true
julia> typeof(("aaa",1,10)) <: Tuple{String,Vararg{Int,3}}
false
NTuple{N,T}
is an alias for
Tuple{Vararg{T,N}}`
julia> typeof((1,10)) <: NTuple{2,Int}
true
Named tuples - NamedTuple{T1,T2,...}
As the name suggests, named tuples are collection similar to ordinary tuples, but whose indexing can accept also a name:
julia> nt = (a=1, b=2.5) #nt = ("a"=1, "b"=2.5) # Error !
(a = 1, b = 2.5)
julia> typeof(nt)
@NamedTuple{a::Int64, b::Float64}
julia> nt[1]
1
julia> nt.a
1
julia> keys(nt)
(:a, :b)
julia> values(nt)
(1, 2.5)
julia> for (k,v) in pairs(nt) println("$k - $v") end
a - 1 b - 2.5
The keys of NamedTuples are symbols, not strings. We'll see symbols in the metaprogramming segment.
Conversion
julia> k = [:a,:b,:c]
3-element Vector{Symbol}: :a :b :c
julia> v = [1,2,3]
3-element Vector{Int64}: 1 2 3
julia> nt = NamedTuple(Dict(:a=>1,:b=>2,:c=>3)) # Order not guaranteed! We are "lucky" here
(a = 1, b = 2, c = 3)
julia> nt = NamedTuple(Dict([k=>v for (k,v) in zip(k,v)])) # Same...
(a = 1, b = 2, c = 3)
julia> v2 = [nt...]
3-element Vector{Int64}: 1 2 3
julia> v3 = [i[1] for i in nt]
3-element Vector{Int64}: 1 2 3
julia> v4 = collect(nt)
3-element Vector{Int64}: 1 2 3
julia> v == v2 == v3 == v4
true
Dictionaries - Dict{Tkey,TValue}
Dictionary are mutable, key-referenced containers:
Mutable | Immutable | |
---|---|---|
Use position | Arrays | Tuples |
Use keys | Dictionaries | Named tuples |
Note that order is not preserved. For insertion-order preservation see OrderedDict
and for sorted dictionaries see SortedDict
, both from the DataStructures.jl package.
Initialisation
julia> mydict = Dict(); #= or better =# mydict = Dict{String,Int64}()
Dict{String, Int64}()
julia> mydict = Dict('a'=>1, 'b'=>2, 'c'=>3)
Dict{Char, Int64} with 3 entries: 'a' => 1 'c' => 3 'b' => 2
Indexing
julia> mydict['a'] #mydict['d'] # error!
1
julia> get(mydict,'d',0) # specific a default if key not found
0
Adding/deleting/checking
julia> mydict['d'] = 4
4
julia> delete!(mydict,'d')
Dict{Char, Int64} with 3 entries: 'a' => 1 'c' => 3 'b' => 2
julia> haskey(mydict, 'a')
true
julia> in(('a' => 1), mydict)
true
julia> typeof('a' => 1)
Pair{Char, Int64}
Conversion
Array - > Dictionary
julia> map((i,j) -> mydict[i]=j, ['e','f','g'], [4,5,6])
3-element Vector{Int64}: 4 5 6
julia> mydict
Dict{Char, Int64} with 6 entries: 'f' => 5 'g' => 6 'a' => 1 'c' => 3 'e' => 4 'b' => 2
julia> k = [:a,:b,:c]
3-element Vector{Symbol}: :a :b :c
julia> v = [1,2,3]
3-element Vector{Int64}: 1 2 3
julia> mydict = Dict([k=>v for (k,v) in zip(k,v)])
Dict{Symbol, Int64} with 3 entries: :a => 1 :b => 2 :c => 3
Dictionary -> Arrays
julia> collect(keys(mydict)) # keys or values alore return an iterator
3-element Vector{Symbol}: :a :b :c
julia> collect(values(mydict))
3-element Vector{Int64}: 1 2 3
Iteration
julia> for (k,v) in mydict println("$k is $v") end
a is 1 b is 2 c is 3
Sets - Set{T}
julia> s = Set(); #= or better =# Set{Int64}()
Set{Int64}()
julia> s = Set([1,2,3,4]) # Only a single `2` will be stored
Set{Int64} with 4 elements: 4 2 3 1
julia> s
Set{Int64} with 4 elements: 4 2 3 1
julia> push!(s,5)
Set{Int64} with 5 elements: 5 4 2 3 1
julia> delete!(s,1)
Set{Int64} with 4 elements: 5 4 2 3
julia> s2 = Set([4,5,6,7])
Set{Int64} with 4 elements: 5 4 6 7
julia> intersect(s,s2)
Set{Int64} with 2 elements: 5 4
julia> union(s,s2)
Set{Int64} with 6 elements: 5 4 6 7 2 3
julia> setdiff(s,s2)
Set{Int64} with 2 elements: 2 3
Date and time - Date
, DateTime
julia> using Dates # a standard library module dealing with dates and times, including periods and calendars
While a DateTime
is a more informative object it is also a much more complex one, as it has to deal with problems as the time zones and the daylight saving
Creation of a date or time object ("input")
From current (local) date/time...
julia> todayDate = today()
2024-01-01
julia> nowTime = now()
2024-01-01T22:55:13.377
julia> typeof(todayDate)
Dates.Date
julia> typeof(nowTime)
Dates.DateTime
julia> Date <: Dates.AbstractTime
true
julia> DateTime <: Dates.AbstractTime
true
julia> nowTimeUnix = time() # The so-called "Unix time, a 64bit integer counting the number of seconds since the beginning of the year 1970
1.7041497134011e9
julia> nowTime = Dates.unix2datetime(nowTimeUnix) # attention this is not local but UTC (Coordinated Universal Time - the Greenwitch time )!
2024-01-01T22:55:13.401
julia> nowTime = Dates.now(Dates.UTC) # an other way to have UTC time
2024-01-01T22:55:13.401
For Time Zone functionalities and conversion, use the external package TimeZone.jl
From a String...
julia> christmasDay = Date("25 Dec 2030", "d u yyyy")
2030-12-25
julia> newYearDay = Date("2031/01/01", "yyyy/m/d")
2031-01-01
julia> christmasLunch = DateTime("2030-12-25T12:30:00", ISODateTimeFormat) # well known string datetime ISO8601 Format
2030-12-25T12:30:00
julia> newYearEvenDinner = DateTime("Sat, 30 Dec 2030 21:30:00", RFC1123Format) # an othe well known format
2030-12-30T21:30:00
Date and time formatters:
y
Year digit (ef yyyy => 2030, yy => 30)m
Month digit (eg m => 3, mm => 03)u
Month name (eg "Jan")U
Month name long (eg "January")e
Day of week (eg "Tue")E
Day of week long (eg "Tuesday")d
Day of month (eg d => 3, dd => 03)H
Hour digit (eg H => 8, HH => 08)M
Minute digit (eg M => 0, MM => 00)S
Second digit (eg S => 0, SS => 00)s
Millisecond digit (eg .000, fixed 3 digits)
Note that the doubling for the digits matters only for using the formatters in the output (see later)
From a tuple of integers: y, m, d, H, M, S, s ...
julia> d = Date(2030, 12) # no need to give it all
2030-12-01
julia> dt = DateTime(2030, 12, 31, 9, 30, 0, 0)
2030-12-31T09:30:00
Date/Time extraction of information ("output")...
To String represerntation...
julia> Dates.format(newYearDay, "dd/m/yy")
"01/1/31"
julia> Dates.format(christmasLunch, "dd/mm/yy H:M:SS")
"25/12/30 12:30:00"
Other...
- Date and DateTime...
julia> year(christmasDay)
2030
julia> isleapyear(christmasDay)
false
julia> month(christmasLunch)
12
julia> monthname(christmasDay)
"December"
julia> day(christmasDay)
25
julia> dayofweek(christmasDay)
3
julia> dayname(christmasDay)
"Wednesday"
julia> daysofweekinmonth(christmasDay) # there are 4 Wednesdays in December 2030
4
julia> dayofweekofmonth(christmasDay) # and the 25th is the 4th of them
4
- Only datetime..
julia> hour(christmasLunch)
12
julia> minute(christmasLunch)
30
julia> second(christmasLunch)
0
Periods and datetime arithmetics
julia> hollidayPeriod = newYearDay - christmasDay # between dates is in days
7 days
julia> longPeriod = Date(2035,6,1) - christmasDay
1619 days
julia> mealPeriod = DateTime(2030,12,31,23,30) - newYearEvenDinner # between datetime is in milliseconds # newYearDay - newYearEvenDinner # error! no mixed
93600000 milliseconds
julia> convert(DateTime,newYearDay)
2031-01-01T00:00:00
julia> convert(Date,newYearEvenDinner) # possible information loss
2030-12-30
julia> mealPeriod = convert(DateTime,newYearDay) - newYearEvenDinner
95400000 milliseconds
julia> typeof(hollidayPeriod)
Dates.Day
julia> typeof(mealPeriod)
Dates.Millisecond
Period hierarchy:
Period
DatePeriod
Year
Month
Week
Day
TimePeriod
Hour
Minute
Second
Millisecond
Microsecond
Nanosecond
julia> # convert(Dates.Year,longPeriod) # going up: error or inexacterror convert(Dates.Millisecond,longPeriod) # going down: fine
139881600000 milliseconds
julia> convert(Dates.Millisecond,mealPeriod)
95400000 milliseconds
julia> canLongPeriod = Dates.canonicalize(longPeriod)
231 weeks, 2 days
julia> typeof(canLongPeriod)
Dates.CompoundPeriod
That the best we can get. We can't "easily" decompose a "period" in years or months... how many days in a month ? 31 or 30 ? And in an year ? A Period
doesn't store information on when it starts. However we can make math with periods based on a specific date/time:
julia> nextChristmas = christmasDay + Year(1) # We can use the constructors of the various periods
2031-12-25
julia> christmasPresentsOpeningTime = christmasLunch + Hour(3)
2030-12-25T15:30:00
julia> thisWeekdayNextCentury = dayname(today()+Year(100))
"Saturday"
Ranges
julia> semesters = Dates.Date(2020,1,1):Dates.Month(6):Dates.Date(2022,1,1)
Dates.Date("2020-01-01"):Dates.Month(6):Dates.Date("2022-01-01")
julia> collect(semesters)
5-element Vector{Dates.Date}: 2020-01-01 2020-07-01 2021-01-01 2021-07-01 2022-01-01
Adjustments
Iterate the past/future days of a date untill some condition is true
julia> sundayBefChristmas = toprev(d -> Dates.dayname(d) == "Sunday", christmasDay)
2030-12-22
julia> lastDayOfThisMonth = tonext(d -> Dates.day(d+Day(1)) == 1, today())
2024-01-31
Find first or last weekday of {month,year} of a given date:
julia> lastTuesdayOfThisMonth = tolast(today(), 2, of=Month) # "2" stands for Tuesday
2024-01-30
julia> firstSundayOfThisYear = tofirst(today(), 7, of=Year) # "7" stands for Sunday
2024-01-07
This page was generated using Literate.jl.