Hey Carl! Indeed, you can think of associations as constituting some "local map" between keys and values (and indeed, that might be part of the reason why they can be "indexed" with single brackets like functions can, though this is just a wild guess).
The primary value of associations in my view comes from the the organizational structure. For example, suppose I have a nested association:
scores=<|"Bob"-><|"Geography"->100,"Mathematics"->80,"Chemistry"->90|>,
"Alice"-><|"Geography"->90,"Mathematics"->100,"Chemistry"->85|>,
"Carol"-><|"Geography"->Missing["Absent"],"Mathematics"->100,"Chemistry"->95|>|>,
Now, without needing to remember which student or score is where, I can do something like:
scores["Bob"]
or:
scores["Bob","Chemistry"]
or:
scores[[All,"Mathematics"]]
This can be very useful for obvious reasons, especially as datasets get larger and more complicated.
We'll discuss this more later in the course, but you may recall that pure functions work with numbered, unnamed slots:
#1+#2&[a,b]
returns:
a+b
But this isn't the only way they can work—they can work with slots named by keys as well:
#cat+#dog&[<|"cat"->1,"dog"->2|>]
will return 3. This lets you write code that not only extracts the appropriate parts very easy, but performs various queries in a super readable and simple way. For example, the following code will select any students who have a chemistry score of 90 or higher:
Select[scores,#Chemistry≥90&]
Finally, from a technical perspective, it is faster to add or remove key-value pairs to an association than to add or remove elements with a list. This doesn't really crop up at the example scales we're talking about here, but can have an effect at larger sizes.