Lesson 5 - Arrays
Learning objectives
Concepts - After completing this lesson, students will be able to:
- Compare and contrast
Vector
,Matrix
, andTuple
types for storing ordered data - Differentiate between scalar and vector properties of
String
s - Explain the uses and limitations of mutable and immutable types
- Recognize when to use copies or references to data
Skills - After completing this lesson, students will be able to:
- Solve bugs that occur from attempting to access keys or indexes that don't exist
- Initialize and grow Vectors of different types
- Use indexes, ranges, and loops to access subsets of data
- Use string joining and interpolation to compose complex strings
Assignments - This lesson is complete when students have:
- Read Chapter 8 and Chapter 10 of Think Julia.
- Run all code examples from Lesson 5 on their own computers
- Cloned the Assignment 5 repository with github classroom.
- Completed assignment 5 with all tests passing.
String as Array
After reading chapters 8 and 10, you might have noticed that String
s act an awful lot like 1D Array
s (Vector
s).
Both String
s and Vector
s:
- are ordered collections (
String
s are collections ofChar
,Vector
s can have any type) - can be indexed and sliced
There are many differences, but chief among them is that Vector
s are "mutable"; that is, we can change the vector by changing individual elements, adding things, or removing things.
julia> v = collect(2:2:10)
5-element Array{Int64,1}:
2
4
6
8
10
julia> push!(v, 42);
julia> pushfirst!(v, -1);
julia> v
7-element Array{Int64,1}:
-1
2
4
6
8
10
42
julia> deleteat!(v, 1:2:7);
julia> v
3-element Array{Int64,1}:
2
6
10
String
s, by contrast, are immutable. This might not be obvious, since you can do things like
julia> s = "a string"
"a string"
julia> s = s * " " * s
"a string a string"
It seems like s
has changed, but it has not changed by altering the actual object - instead, we constructed an entirely new string and just reassigned s
to the new String
.
- Assign an empty vector (
[]
) to the variablev1
, then try topush!
anInt64
,Float64
, andString
to it. What is thetypeof
theVector
? - Assign
[1.2, 3, 4]
to the variablev2
. What is the type of the second elementt (v2[2]
)? Is that what you expected? - Use
push!()
to add the integer5
to the vectorv2
. What is the type ofv2[4]
? - Use
push!()
to add theString
"6"
to the vectorv2
. What happens?
String
s themselves are not Vector
s, but we can use Vector
s of Char
s to act like mutable String
s.
julia> vc = collect("Collect makes vector")
20-element Array{Char,1}:
'C'
'o'
'l'
'l'
'e'
'c'
't'
' '
'm'
'a'
'k'
'e'
's'
' '
'v'
'e'
'c'
't'
'o'
'r'
julia> push!(vc, 's');
julia> join(vc)
"Collect makes vectors"
The join()
function takes a vector of String
s or Char
s and creates a new string.
Remember that you can use the help REPL (press ?
at the REPL) to view the docstring of join()
.
The join()
function can also take optional arguments that can put a String
in between each thing that's join()
ed,
julia> join(["I", "love", "the", "julia", "language!"], " ๐ ")
"I ๐ love ๐ the ๐ julia ๐ language!"
and something different between the last two values
julia> join(["Head", "shoulders", "knees", "toes"], ", ", ", and ")
"Head, shoulders, knees, and toes"
Aliasing
Make sure you've read the section on "aliasing" in Think Julia prior to answering the following questions. Even if you already read it, it's worth reading again - this is a constant source of hard-to-find bugs.
For each of the following questions, first try to predict the answer, then check your answer at the REPL. If you were wrong, try to explain the correct answer.
The follwing code assigns 3 variables (
a
,b
, andc
) to the float 6.02e24, then reassigns one of them (a
) to the float3.14
.julia> a = b = c = 6.02e24 6.02e24 julia> a = 3.14 3.14
What is the value of
b
?Can you assign
c
to anInt64
?The following code assigns 3 variables (
u
,v
,w
) to an empty Integer vector, thenpush!
es the integer12
to one of them (u
)```julia julia> u = v = w = Int64[] 0-element Array{Int64,1}
julia> push!(u, 12) 1-element Array{Int64,1}: 12 ```
What is the value of v
?
Can you
push!()
aFloat64
tow
?Which of the following have the same type as
m
ifm = [1, 4]
?n = [5,4,3,2,1]
o = Int64[]
p = ["2", "1"]
- `q = [1.2, 3.4]
Hint: you can check by doing eg
n isa (typeof(m))
Maps and filters revisited
In chapter 10 of Think Julia, you are introduced to the concept of "map" and "filter" functions, which apply a function to each element of a collection, or return only elements that meet a condition respectively.
In the chapter, the examples shown are of hand-written map and filter functions written with loops, but these pattterns are so useful that there are map()
and filter()
functions, each of which take a function as the first argument, and a collection as the second argument.
For example,
function add3(x)
return x + 3
end
v = map(add3, [1,2,3,4])
4-element Array{Int64,1}:
4
5
6
7
This is the same as
v = Int64[]
for x in [1,2,3,4]
push!(v, add3(x))
end
This type of map()
returns a copy of the vector, so the original data will not be altered, but you can also use map!()
with the same syntax to mutate the underlying vector.
Similarly, one can use filter()
(or, to mutate, filter!()
) to perform a filtering function. In this case, the function passed as the first argument must be a boolean function (anything that returns true
will be kept).
original = [3.14, 8.5, 25.3, 1.0]
function lessthan5(x)
return x < 5
end
newv = filter(lessthan5, original)
2-element Array{Float64,1}:
3.14
1.0
is the same as
newv = Float64[]
for x in original
if lessthan5(x)
push!(newv, x)
end
end