Mix.install([
{:jason, "~> 1.4"},
{:kino, "~> 0.9", override: true},
{:youtube, github: "brooklinjazz/youtube"},
{:hidden_cell, github: "brooklinjazz/hidden_cell"}
])
Upon completing this lesson, a student should be able to answer the following questions.
- When should you use a MapSet vs a list?
- What are the performance impacts of MapSets, Maps, and Keyword Lists?
In this lesson, we will study the internal details of Maps, MapSets, and Keyword Lists to determine when to use each data type.
Keyword lists have the same properties as Lists.
Operation | Time Complexity |
---|---|
Access | |
Search | |
Insertion |
|
Deletion |
|
Because they are simply lists of {:atom, value}
Tuples.
[{:key1, "value"}, {:key2, "value"}] == [key1: "value", key2: "value"]
Maps are a key-value data type that typically has
Operation | Time Complexity |
---|---|
Access | |
Search | |
Insertion |
|
Deletion |
|
Maps with 32
or fewer keys are sorted lists. Therefore they have
Notice that the map below retains its sort order.
map = Map.new(1..32, fn x -> {x, "#{x}"} end)
Under the hood, a map with 32
or fewer keys uses a sorted list.
Generally, we should avoid relying on this property. When a map grows beyond 32
keys, it loses its sorting order.
Notice the map below is no longer ordered
now that it has 33
keys.
map = Map.new(1..33, fn x -> {x, "#{x}"} end)
Maps in Elixir are Hash Array Mapped Trie (HAMT) structures.
We won't dive deeply into the implementation of this data structure as it is beyond the scope of this course.
For practical purposes, be aware most operations on a map will have
Maps scale better for large values when compared with lists or keyword lists, which grow linearly instead of logarithmically.
Accessing any key in a map with a million elements is nearly instant, regardless of which key is accessed!
First, we'll create the large map. This may take a moment.
large_map = Map.new(1..10_000_000, fn x -> {x, x} end)
While creating the map took some time, reading a value should be extremely fast.
Evaluate the cell below and notice how quickly we can access a value. Try changing key
to any integer between 0
and 999_999
. Notice there is no significant affect on the speed of accessing a value.
key = 500_000
{micro_seconds, _result} = :timer.tc(fn -> Map.get(large_map, key) end)
micro_seconds
On the other hand, Lists are slow compared to Maps because they need to enumerate each element.
large_list = Enum.to_list(1..1_000_000)
Try changing index
to any integer between 0
and 999_999
and notice that the larger the index value, the slower it takes to access an element.
index = 500_000
{micro_seconds, _result} = :timer.tc(fn -> Enum.at(large_list, index) end)
micro_seconds
MapSets are a set data structure. They function like a list that only allows non-duplicate values.
MapSet.new([1, 2, 3])
MapSets ignore duplicate values.
MapSet.new([1, 2, 3, 3])
MapSets are Maps under the hood, so they inherit the same performance properties as Maps.
Operation | Time Complexity |
---|---|
Access | |
Search | |
Insertion |
|
Deletion |
|
The MapSet module contains functions for working with MapSets.
Here's a few to get you started:
new/1
create a new mapset.put/2
add an element into a mapset.delete/2
remove an element from a mapset.
A MapSet can contain any value. Keep in mind that order is not guaranteed.
MapSet.new(["1", 2, :three])
put/2
adds any non-duplicate element to a mapset.
set = MapSet.new([1, 2, 3])
MapSet.put(set, 4)
Duplicates will simply be ignored.
set = MapSet.new([1, 2, 3])
MapSet.put(set, 2)
delete/2
removes an element from a MapSet.
set = MapSet.new([1, 2, 3])
MapSet.delete(set, 2)
MapSet is enumerable. However, any Enum function with a MapSet returns a list.
MapSet.new([1, 2, 3]) |> Enum.map(fn each -> each + 1 end)
Generally, Lists are overused and can often be a MapSet instead. If you have a list where there should never be duplicate elements and order is not important, it's usually more performant to use a MapSet.
Create a MapSet with the elements 1, 2, 3
. Use MapSet.member?/2 to check if your MapSet contains
the element 2
. Your answer should return true
.
DockYard Academy now recommends you use the latest Release rather than forking or cloning our repository.
Run git status
to ensure there are no undesirable changes.
Then run the following in your command line from the curriculum
folder to commit your progress.
$ git add .
$ git commit -m "finish Maps, Mapsets, And Keyword Lists reading"
$ git push
We're proud to offer our open-source curriculum free of charge for anyone to learn from at their own pace.
We also offer a paid course where you can learn from an instructor alongside a cohort of your peers. We will accept applications for the June-August 2023 cohort soon.