Collections are groups of elements. These elements are values of different Julia types. Storing elements in collections is one of the most useful operations in computing.
Arrays are collections of values separated with commas and placed inside of a set of square brackets. They can be represented in column or in row form.
# A column vectorarray1=[1,2,3]
3-element Array{Int64,1}: 1 2 3
The typeof()
function shows that array1
is an instance of an array object, containing integer values.
# The type of the object array1typeof(array1)
Array{Int64,1}
Below we create array2
. Note that there are only spaces between the elements.
# A row vectorarray2=[123]
1×3 Array{Int64,2}: 1 2 3
The transpose()
function will create a linear algebra transpose of our column vector, array1
.
# The transposetranspose(array1)
1×3 LinearAlgebra.Transpose{Int64,Array{Int64,1}}: 1 2 3
When the types of the elements are not the same, all elements inherit the highest type.
# With a mix of types, all the elements inherent the "highest" typearray2=[1,2,3.0]
3-element Array{Float64,1}: 1.0 2.0 3.0
# Index for one of the original integers will be Float64array2[1]
1.0
Arrays can have more than one dimension (here dimension does not refer to the number of elements in a vector, representing a vector field).
# Column-wise entry of multidimensional arrayarray3=[[1,2,3][4,5,6][7,8,9]]
3×3 Array{Int64,2}: 1 4 7 2 5 8 3 6 9
# Row-wise entry of multidimensional arrayarray4=[[123];[456];[789]]
3×3 Array{Int64,2}: 1 2 3 4 5 6 7 8 9
The length()
function returns the number of elements.
# Length of array3length(array3)
9
length(array4)
9
Since the two arrays above were created differently, let's take a look at indexes of their elements.
# Index order of column-wise arrayforiin1:length(array3)println("Element $(i) is ",array3[i])end
Element 1 is 1 Element 2 is 2 Element 3 is 3 Element 4 is 4 Element 5 is 5 Element 6 is 6 Element 7 is 7 Element 8 is 8 Element 9 is 9
# Index order of row-wise arrayforiin1:length(array4)println("Element $(i) is ",array4[i])end
Element 1 is 1 Element 2 is 4 Element 3 is 7 Element 4 is 2 Element 5 is 5 Element 6 is 8 Element 7 is 3 Element 8 is 6 Element 9 is 9
Elements can be repeated using the repeat()
function.
# Using repeat() to repeat column elementsrepeat([1,2],3)
6-element Array{Int64,1}: 1 2 1 2 1 2
# Using repeat() to repeat row elementsrepeat([12],3)
3×2 Array{Int64,2}: 1 2 1 2 1 2
The range()
function creates a range object. The first argument is the value of the first element. The step =
argument specifies the step-size, and the length =
argument specifies how many elements the array should have.
# Using range(start, step, number of elements)range(1,step=1,length=10)
1:1:10
We can change the range object into an array using the collect()
function.
# Create collections using the collect() functioncollect(range(1,step=1,length=10))
10-element Array{Int64,1}: 1 2 3 4 5 6 7 8 9 10
# Short-hand syntaxcollect(1:10)
10-element Array{Int64,1}: 1 2 3 4 5 6 7 8 9 10
We can create empty arrays as placeholders.
# Creating empty array with two rows and three columnsarray5=Array{Union{Missing,Int}}(missing,2,3)
2×3 Array{Union{Missing, Int64},2}: missing missing missing missing missing missing
Reshaping is achieved using the reshape()
function.
# Reshapingreshape(array5,3,2)
3×2 Array{Union{Missing, Int64},2}: missing missing missing missing missing missing
Every element in an arrays has an index (address) value. We already saw this above when we created a for-loop to cycle through the values of our row vs. column created arrays.
# Creating a 10 x 5 array with each element drawn randomly from value 10 through 20array6=rand(10:20,10,5)
10×5 Array{Int64,2}: 18 14 10 13 14 16 12 18 11 20 17 11 10 18 12 18 11 13 10 13 17 20 14 20 12 20 16 11 17 10 11 18 20 10 17 16 19 17 13 10 14 20 10 14 14 19 19 12 12 16
Indexing is indicated with square brackets. For arrays with rows and columns, the index values will be in the form [row, column]
. A colon serves as short-hand syntax indicating all values.
#All rows in first columnarray6[:,1]
10-element Array{Int64,1}: 18 16 17 18 17 20 11 16 14 19
# Rows two through five of second columnarray6[2:5,2]
4-element Array{Int64,1}: 12 11 11 20
# Values in rows 2, 4, 6, and in columns 1 and 5array6[[2,4,6],[1,5]]
3×2 Array{Int64,2}: 16 20 18 13 20 10
# Values in row 1 from column 3 to the last columnarray6[1,3:end]
3-element Array{Int64,1}: 10 13 14
Boolean logic can be used to select values based on rules. Below we check if each value in column one is equal to or greater than $12$.
# Boolean logic (returning only true or false)array6[:,1].>12
10-element BitArray{1}: true true true true true true false true true true
We can add values to an array using the push!()
function. Many functions in Julia have an added exclamation mark, called a bang. It is used to make permanent changes to the values in a computer variable.
# Creating a five element arrayarray7=[1,2,3,4,5]# Permanantly append 10 to end of arraypush!(array7,10)
6-element Array{Int64,1}: 1 2 3 4 5 10
The pop!()
function removes the last element (the bang makes it permanent).
pop!(array7)
10
We can also change the value of an element by using its index.
# Change second element value to 1000array7[2]=1000
1000
# Viewing the changearray7
5-element Array{Int64,1}: 1 1000 3 4 5
List comprehension is a term that refers to the creating of an array using a recipe. View the following example.
# An example of list comprehensionarray8=[3*iforiin1:5]
5-element Array{Int64,1}: 3 6 9 12 15
The Julia syntax is very expressive, as the above example shows. Square brackets indicate that we are creating a list. The expression, 3 * i
indicates what we want each element to look like. The for-loop uses the placeholder over which we wish to iterate, together with the range that we require.
This allows for very complex array creation, which makes it quite versatile.
# Column-wise collection iterating through second element firstarray9=[a*bforain1:3,bin1:3]
3×3 Array{Int64,2}: 1 2 3 2 4 6 3 6 9
Arithmetic operations on arrays are performed through the process of broadcasting. Below we add $1$ to each element in array9
.
# Elementwise addition of a scalar using dot notationarray9.+1
3×3 Array{Int64,2}: 2 3 4 3 5 7 4 7 10
When arrays are of similar shape, we can do elemnt wise addition.
# Elementwise addition of similar sized arraysarray7+array8
5-element Array{Int64,1}: 4 1006 12 16 20
While it is nice to have a complete set of elements, data is often missing. Missing
is a Julia data type that provides a placeholder for missing data in a statistical sense. It propagates automatically and its equality as a type can be tested. Sorting is possible since missing is seen as greater than other values.
# Propagationmissing+1
missing
missing>1
missing
[1,2,3,missing,5]+[10,20,30,40,50]
5-element Array{Union{Missing, Int64},1}: 11 22 33 missing 55
# Checking equality of value using ==# Cannot return true or false since value is not knownmissing==missing
missing
# Checking equality of type with ===missing===missing
true
# Checking type equality with isequal()isequal(missing,missing)
true
# Sorting with isless()isless(1,missing)
true
# Checking on infinityisless(Inf,missing)
true
We can create an array of zeros.
# A 3 x 3 array of integer zerosarray11=zeros(Int8,3,3)
3×3 Array{Int8,2}: 0 0 0 0 0 0 0 0 0
Here is an array of ones.
# A 3 x 3 array of floating point onesarray12=ones(Float16,3,3)
3×3 Array{Float16,2}: 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
Boolean values are also allowed.
# Array of true (bit array) valuesarray13=trues(3,3)
3×3 BitArray{2}: true true true true true true true true true
We can even fill an array with a specified value.
# Fill an array with elements of value xarray14=fill(10,3,3)
3×3 Array{Int64,2}: 10 10 10 10 10 10 10 10 10
We have already seen that elemnts of different types all inherit the highest type. We can in fact, change the type manually, with the convert function. As elsewhere in Julia, the dot opetaror maps the function to each element of a list.
# Convert elements to a different data typeconvert.(Float16,array14)
3×3 Array{Float16,2}: 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0
Arrays can be concatenated.
# Concatenate arrays along rows (makes rows)array15=[1,2,3]array16=[10,20,30]cat(array15,array16,dims=1)
6-element Array{Int64,1}: 1 2 3 10 20 30
# Same as abovevcat(array15,array16)
6-element Array{Int64,1}: 1 2 3 10 20 30
# Concatenate arrays along columns (makes columns)cat(array15,array16,dims=2)
3×2 Array{Int64,2}: 1 10 2 20 3 30
# Same as abovehcat(array15,array16)
3×2 Array{Int64,2}: 1 10 2 20 3 30
Tuples are immutable collections. Immutable refers to the fact that the values are set and cannot be changed. This type is indicated by the use of parenthesis instead of square brackets.
# Tuples with mixed typestuple1=(1,2.,π,4,"Julia")
(1, 2.0, π = 3.1415926535897..., 4, "Julia")
Let's check on the values and types of each element.
# For loop to look at value and type of each elementforiin1:length(tuple1)println(" The value of the tuple at index number $(i) is $(tuple1[i]) and the type is $(typeof(tuple1[i])).")end
The value of the tuple at index number 1 is 1 and the type is Int64. The value of the tuple at index number 2 is 2.0 and the type is Float64. The value of the tuple at index number 3 is π = 3.1415926535897... and the type is Irrational{:π}. The value of the tuple at index number 4 is 4 and the type is Int64. The value of the tuple at index number 5 is Julia and the type is String.
Tuples are useful as each elemnt can be named.
# Each element can be nameda,b,c,seven=(1,3,5,7)a
1
seven
7
A range can be used to reverse the order of a tuple.
# Reverse order index (can be done with arrays too)tuple1[end:-1:1]
("Julia", 4, π = 3.1415926535897..., 2.0, 1)
Arrays can be made up of elemnts of different length.
# Mixed length tuplestuple2=((1,2,3),1,2,(3,100,1))
((1, 2, 3), 1, 2, (3, 100, 1))
# Element 4tuple2[4]
(3, 100, 1)
# Element 2 in element 4tuple2[4][2]
100
Dictionaries are collection sof key-value pairs.
# 1 Example of a dictionarydictionary1=Dict(1=>77,2=>66,3=>1)
Dict{Int64,Int64} with 3 entries: 2 => 66 3 => 1 1 => 77
In the example above we have key-values of 1,2,3
and value-values of 77,66,1
.
# The => is shorthand for the Pair() functiondictionary2=Dict(Pair(1,100),Pair(2,200),Pair(3,300))
Dict{Int64,Int64} with 3 entries: 2 => 200 3 => 300 1 => 100
We can specify the types used in a dict.
# 2 Specifying typesdictionary3=Dict{Any,Any}(1=>77,2=>66,3=>"three")
Dict{Any,Any} with 3 entries: 2 => 66 3 => "three" 1 => 77
# We can get a bit crazydictionary4=Dict{Any,Any}("a"=>1,(2,3)=>"hello")
Dict{Any,Any} with 2 entries: (2, 3) => "hello" "a" => 1
It is perhaps more useful to use symbols (colon symbol and a name) as key values. We can then refer to the key-name when we want to inquire about its value.
# Using symbols as keysdictionary5=Dict(:A=>300,:B=>305,:C=>309)dictionary5[:A]
300
We can check on the key-value pairs in a dictionary.
# Using in() to check on key-value pairsin((:A=>300),dictionary5)
true
Change value using the key is easy to perform.
# Changing an existing valuedictionary5[:C]=1000dictionary5
Dict{Symbol,Int64} with 3 entries: :A => 300 :B => 305 :C => 1000
The delete!()
function permanently deletes a key-value pair.
# Using the delete!() functiondelete!(dictionary5,:A)
Dict{Symbol,Int64} with 2 entries: :B => 305 :C => 1000
We can list both the keys and the values in a dictionary.
# The keys of a dictionarykeys(dictionary5)
Base.KeySet for a Dict{Symbol,Int64} with 2 entries. Keys: :B :C
values(dictionary5)
Base.ValueIterator for a Dict{Symbol,Int64} with 2 entries. Values: 305 1000
Through the use of iteration, we can get creative in the creation and interrogation of a dictionary.
# Creating a dictionary with automatic keysprocedure_vals=["Appendectomy","Colectomy","Cholecystectomy"]procedure_dict=Dict{AbstractString,AbstractString}()# An empty dictionary with types specifiedfor(s,n)inenumerate(procedure_vals)procedure_dict["x_$(s)"]=nend
procedure_dict
Dict{AbstractString,AbstractString} with 3 entries: "x_1" => "Appendectomy" "x_2" => "Colectomy" "x_3" => "Cholecystectomy"
# Iterating through a dictionary by key and valuefor(k,v)inprocedure_dictprintln(k," is ",v)end
x_1 is Appendectomy x_2 is Colectomy x_3 is Cholecystectomy
Lastly, we can sort using iteration.
# Sortingdictionary6=Dict("a"=>1,"b"=>2,"c"=>3,"d"=>4,"e"=>5,"f"=>6)# Sorting using a for loopforkinsort(collect(keys(dictionary6)))println("$(k) is $(dictionary6[k])")end
a is 1 b is 2 c is 3 d is 4 e is 5 f is 6