9.3. Dictionary

We have explored several ways of storing a collection of the same type of data:

  • arrays: built-in syntax, unchanging size of the collection

  • List: generic class type, allows the size of the collection to grow

Both approaches allow reference to data elements using a numerical index between square brackets, as in words[i]. The index provides an order for the elements, but there is no meaning to the index beyond the sequence order.

Sometimes, we want to look up data based on a more meaningful key, as in a dictionary: given a word, you can look up the definition.

C# uses the type name Dictionary, but with greater generality than in nontechnical use. In a regular dictionary, you start with a word, and look up the definition. The generalization is to have some piece of data that leads you to (or maps to) another piece of data. The computer science jargon is that a key leads you to a value. In a normal dictionary, these are both likely to be strings, but in the C# generalization, the possible types of key and value are much more extensive. Hence the generic Dictionary type requires you to specify both a type for the key and a type for the value.

9.3.1. Creating a Dictionary

We can initialize an English-Spanish dictionary e2sp with

Dictionary<string, string> e2sp = new Dictionary<string, string>();

That is quite a mouthful! The C# var keyword (implicitly-typed local variable) syntax is handy to shorten it as you do not have to repeat the type name:

var e2sp = new Dictionary<string, string>();

The general generic type syntax therefore is:

Dictionary< keyType, valueType >

For example, if you are counting the number of repetitions of words in a document, you are likely to want a Dictionary mapping each word to its number of repetitions so far:

var wordCount = new Dictionary<string, int>();

If your friends all have a personal list of phone numbers, you might look them up with a dictionary with a string name for the key and a List of personal phone number strings for the value. The type could be Dictionary<string, List<string>>. This example illustrates how one generic type can be built on another.

There is no restriction on the value type. There is one important technical restriction on the key type: it should be immutable. .. This has to do with the implementation referenced in dictionary-efficiency.

9.3.2. Accessing Data in Dictionary

Similar to an array or List, you can assign and reference elements of a Dictionary, using square bracket notation. The difference is that the reference is through a key, not a sequential index, as in:

e2sp["one"] = "uno";
e2sp["two"] = "dos";

or, you can use the Dictionary.Add() method:

e2sp.Add("three", "tres");

csharprepl displays dictionaries in its own special form, as a table showing the {key, value} pairs and type. Here is a longer csharprepl sequence:

> Dictionary<string, string> e2sp = new Dictionary<string, string>();

> e2sp
Dictionary<string, string>(0)

> e2sp["one"] = "uno";
> e2sp["two"] = "dos";
> e2sp.Add("three", "tres");
> e2sp.Count                     // the Count property gives the length of the dictionary
3
> e2sp;
Dictionary<string, string>(3)
┌──────┬─────────────────────┬──────────────────────────────┐
│ Name │ Value               │ Type                         │
├──────┼─────────────────────┼──────────────────────────────┤
│ [0]  │ { "one", "uno" }    │ KeyValuePair<string, string> │
│ [1]  │ { "two", "dos" }    │ KeyValuePair<string, string> │
│ [2]  │ { "three", "tres" } │ KeyValuePair<string, string> │
└──────┴─────────────────────┴──────────────────────────────┘

 > Console.WriteLine("{0}, {1}; {2}", e2sp["one"], e2sp["two"], e2sp["three"])
      uno, dos; tres

As you can see, we using the key to refer to the value of a dictionary entry. If a key-value pair already exists, you may not Add() a value to the key, but you can update date it using the Item[] property (the indexer[] square brackets) such as dict[“aaa”] = “AAA”;

If you want to iterate through a whole Dictionary, you will want the syntax below, with foreach and the property Keys:

> foreach (string s in e2sp.Keys) {
>    Console.WriteLine(s);
> }
one
two
three

To loop through the dictionary and access both the key and value in each entry, you may do:

> foreach (var entry in e2sp.Keys) {
>    Console.WriteLine("{0} : {1}", entry.Key, entry.Value);
> }

In this example, we use an implicitly-typed variable entry to ask the compiler to infer the type. We then use the .Key and .Value properties to refer to the data.

The documentation for Dictionary says that you cannot depend on the order of processing with foreach, though the present implementation remembers the order in which keys were added.

9.3.3. Properties and Methods in Dictionary

There are plenty of properties and methods built in in the Dictionary class in addition to .Add() and .Count, .Key, .Value as aforementioned.

It is often useful to know if a key is already in a Dictionary: Note the method ContainsKey:

> e2sp.ContainsKey("seven")
false
> e2sp.ContainsKey("three")
true

The method Remove takes a key as parameter. Like a List and other collections, a Dictionary has a Clear method:

> e2sp.Count;
┌───────────────────────────────────────────────────CompilationErrorException────────────────────────────────────────────────────┐
│ (1,1): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement │
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ e2sp.Count
> e2sp.Count
3

> e2sp.Remove("two")
true
> e2sp.Count
2

> e2sp
Dictionary<string, string>(2)
┌──────┬─────────────────────┬──────────────────────────────┐
│ Name │ Value               │ Type                         │
├──────┼─────────────────────┼──────────────────────────────┤
│ [0]  │ { "one", "uno" }    │ KeyValuePair<string, string> │
│ [1]  │ { "three", "tres" } │ KeyValuePair<string, string> │
└──────┴─────────────────────┴──────────────────────────────┘

> e2sp.Clear()
> e2sp
Dictionary<string, string>(0)
> e2sp.Count
0