Dictionaries¶
Time Complexity |
Space Complexity |
||
Access |
Search |
Insert / Delete |
O(n) |
N/A |
O(1) |
O(1) |
|
A “dictionary” in programming terms can be compared to an actual dictionary: some word (or ‘key’)
is associated with some definition (or ‘value’). The difference is, with a dictionary in programming,
these “keys” and “values” can be anything (any type). For instance, "pi" can be associated with 3.14,
or the capital letter 'P' can be associated with "Pinocchio".
You might ask, what’s the use of this? Compared with the other data structures, dictionaries are extremely efficient. Instead of going through the entire dictionary to find something, like you might with an array, or using binary search with numbers, if you give a dictionary a “key” it gives you the “value” almost instantly (read: O(1) averge time), no matter how big the dictionary is (generally).
The reason this works involves a “hash function” and a “hash table”. But you can imagine there’s just some magical function that gives you the value from the key, and have a pretty good idea. It works sort of like the dewey decimal system, where given the index it’s generally known where the corresponding book is. But there’s more math involved.
This structure is often used to make algorithms more efficient by remembering associations, but you can see that in the “advanced” section. This example has the first three letters and the corresponding words in the phonetic alphabet adopted by NATO to make communication clearer and more definite.
Comments are included to show what task is being done at which line, and the same syntax should be used for most dictionaries.
#include <iostream>
#include <unordered_map>
using namespace std;
int main() {
// Declaration
unordered_map<char, string> dict;
// Add / change values
dict['a'] = "Alpha";
dict['b'] = "Bravo";
dict['c'] = "Charlie";
// Get specific values
cout << "a is for " << dict['a'] << endl;
// Get size
cout << "number of things: " << dict.size() << endl;
// Check if key is present
cout << boolalpha;
cout << "a: " << (dict.find('a') != dict.end()) << endl;
cout << "d: " << (dict.find('d') != dict.end()) << endl;
// Accessing all values
for (auto entry : dict) //c++ 11
cout << entry.first << " " << entry.second << endl;
}
using System.Collections.Generic;
class Program {
static void Main(string[] args) {
// Declaration
Dictionary<char, string> dict = new Dictionary<char, string>();
// Add / change values
dict['a'] = "Alpha";
dict['b'] = "Bravo";
dict['c'] = "Charlie";
// Get specific values
System.Console.WriteLine("a is for " + dict['a']);
// Get size
System.Console.WriteLine("size: " + dict.Count);
// Check if key is present
System.Console.WriteLine("a: " + dict.ContainsKey('a'));
System.Console.WriteLine("d: " + dict.ContainsKey('d'));
// Accessing all values
foreach(KeyValuePair<char, string> entry in dict)
System.Console.WriteLine(entry.Key + " " + entry.Value);
}
}
import java.util.*;
public class dictionary {
public static void main(String[] args) {
// Declaration
Map<Character, String> dict = new HashMap<Character, String>();
// Add / change values
dict.put('a', "Alpha");
dict.put('b', "Bravo");
dict.put('c', "Charlie");
// Get specific values
System.out.println(dict.get('a'));
// Get size
System.out.println("size: " + dict.size());
// Check if key is present
System.out.println("a: " + dict.containsKey('a'));
System.out.println("d: " + dict.containsKey('d'));
// Accessing all values
for(Character key : dict.keySet())
System.out.println(key + " " + dict.get(key));
}
}
// Declaration
var dict = {};
// Add / change values
dict['a'] = "Alpha";
dict['b'] = "Bravo";
dict['c'] = "Charlie";
// Get specific values
console.log(dict['a']);
// Get size
console.log("size: " + Object.keys(dict).length);
// Check if key is present
console.log('a' in dict);
console.log('d' in dict);
// Accessing all values
Object.keys(dict).forEach( function(key){
console.log(key, dict[key]);
});
# Declaration
dict = {}
# Add / change values
dict['a'] = "Alpha"
dict['b'] = "Bravo"
dict['c'] = "Charlie"
# Get specific values
print(dict['a'])
#or
print(dict.get('a'))
# Get size
print(len(dict))
# Check if key is present
print('a' in dict)
print('d' in dict)
# Accessing all values
for key in dict:
print(key, dict[key])
// Declaration
var dict = [Character : String]()
// Add / change values
dict["a"] = "Alpha"
dict["b"] = "Bravo"
dict["c"] = "Charlie"
// Get specific values
print(dict["a"]!)
// Get size
print(dict.count)
// Check if key is present
print(dict["a"] != nil)
print(dict["d"] != nil)
// Accessing all values
for(key, value) in dict{
print(key, value)
}
Notes¶
The import statement #include <unordered_map> should be used for a dictionary
(referred to as an “unordered map” in C++).
It should be noted that almost any type (including custom types) can be used for the values of a dictionary, but using custom types for the keys requires your own hash function, which is a mess in itself. C++ defined types, however, are usually fine.
boolalpha is passed to cout to change 1 and 0 boolean outputs to true
and false.
the .find() function results in the dict.end() pointer if there is no key, so that’s why they
can be compared with != to check if the key is there.
In c++ 11, a dictionary (and most other data structures) can be iterated through with a “range-based for loop”. This loop automatically knows the type and covers the entire data structure in a concise way with the syntax
for (auto yourVar : yourStructure){//do something with 'yourVar'}Note
There is one line marked as C++ 11 here, so add “-std=c++11” after “g++” when compiling if it doesn’t work.
If you’re stuck with an older version of C++, a dictionary can also be iterated through like this:
for (unordered_map<char, string>::iterator it = dict.begin(); it != dict.end(); it++){cout << it->first << " " << it->second << endl;}This uses an “iterator” pointer, used in the standard library.
The import statement using System.Collections.Generic; should be used.
This uses a foreach loop, a loop in C# that goes through the variables in a container with the syntax
foreach(KeyValuePair<char, string> yourVar in dict)// do something with yourVar.Key and yourVar.ValueThe import statement import java.util.*; should be used.
dict.keySet() returns the keys of the dictionary.
A “range-based” for loop is used. This gives you each value in an array / container. It has the syntax
for(typeOfVar yourVar : someContainer)//do stuff with "yourVar"Conveniently, all JavaScript objects are dictionaries by default. This means they can be declared with curly brackets, e.g.:
var dict = {}
The syntax Object.keys(dictionary) returns the keys of the dictionary.
A “range-based” for loop is used. This gives you each value in an array / container. It has the syntax
someArray.foreach( function(yourVar){//do stuff with "yourVar"});Where yourVar is each item and someArray is your array.
A “range-based” for loop is used. This gives you each value in an array / container. It has the syntax
for yourVar in someArray:#do stuff with yourVarDoing this with a dictionary gives keys as yourVar.
Swift has what are known as “optionals”. These are variables which may or may not exist. When accessing
a dictionary, instead of returning something like a normal string, a “string optional” is returned, which
is either a string or nil (undefined). These are represented as string? when
debugging in the console, and are represented similarly for other “optional” types.
When using an “optional” and you know it’s defined, you can force it to the original type with the !
operator.
Often, the value of an optional is checked with the syntax
if let thing = someOptional {//do stuff with thing}This is safer than other languages if you don’t know if a variable is defined.
Also, a “range-based” for loop is used. This gives you each value in an array / container. It has the syntax
for yourVar in someArray{#do stuff with yourVar}When doing this with a dictionary, something like (key, value) should be used in place of yourVar.
The words can be anything, however having two things in parenthesis gets you the keys and values.