Exercises in this lecture   Go to the notes, in which this exercise belongs -- Keyboard shortcut: 'u'   Alphabetic index   Course home   

Exercise solution:
Switching from Dictionary to SortedDictionary


We need to hand an IComparer instead of a IEqualityComparer to the SortedDictionary constructor. The reason is that a SortedDcitionary needs a ordering (like CompareTo), and not just equality.

using System;
using System.Collections.Generic;

class DictionaryDemo{

  public static void Main(){

    IDictionary<Person, BankAccount> bankMap = 
      new SortedDictionary<Person,BankAccount>(new NewPersonComparer());

    // Make bank accounts and person objects
    BankAccount ba1 =  new BankAccount("Kurt", 0.01),
                ba2 =  new BankAccount("Maria", 0.02),
                ba3 =  new BankAccount("Francoi", 0.03),
                ba4 =  new BankAccount("Unknown", 0.04),
                ba5 =  new BankAccount("Anna", 0.05);

    Person p1 = new Person("Kurt"),
           p2 = new Person("Maria"),
           p3 = new Person("Francoi"),
           p4 = new Person("Anna");

    ba1.Deposit(100); ba2.Deposit(200); ba3.Deposit(300); 

    // Populate the bankMap: 
    bankMap.Add(p1, ba1); 
    bankMap.Add(p2, ba2);
    bankMap.Add(p3, ba3);
    bankMap.Add(p4, ba5);
    ReportDictionary("Initial map", bankMap);

    // Print Kurt's entry in the map:
    Console.WriteLine("{0}\n", bankMap[p1]);

    // Mutate Kurt's entry in the map
    bankMap[p1] = ba4;
    ReportDictionary("bankMap[p1] = ba4;", bankMap);

    // Mutate Maria's entry in the map. PersonComparer crucial!
    ba4.Deposit(400);
    bankMap[new Person("Maria")] = ba4;
    ReportDictionary("ba4.Deposit(400);  bankMap[new Person(\"Maria\")] = ba4;", bankMap);

    // Add p3 yet another time to the map
    // Run-time error: An item with the same key has already been added.
/*  bankMap.Add(p3, ba1);
    ReportDictionary("bankMap.Add(p3, ba1);", bankMap); 
 */

    // Try getting values of some given keys
    BankAccount ba1Res = null,
                ba2Res = null;
    bool res1 = false,
         res2 = false;
    res1 = bankMap.TryGetValue(p2, out ba1Res);        
    res2 = bankMap.TryGetValue(new Person("Anders"), out ba2Res);
    Console.WriteLine("Account: {0}. Boolean result {1}", ba1Res, res1);
    Console.WriteLine("Account: {0}. Boolean result {1}", ba2Res, res2);
    Console.WriteLine();

    // Remove an entry from the map
    bankMap.Remove(p1);
    ReportDictionary("bankMap.Remove(p1);", bankMap);

    // Remove another entry - works because of PersonComparer
    bankMap.Remove(new Person("Francoi"));
    ReportDictionary("bankMap.Remove(new Person(\"Francoi\"));", bankMap);
  }

  public static void ReportDictionary<K, V>(string explanation, 
                                            IDictionary<K,V> dict){
    Console.WriteLine(explanation);
    foreach(KeyValuePair<K,V> kvp in dict)
      Console.WriteLine("{0}: {1}", kvp.Key, kvp.Value);
    Console.WriteLine(); 
  }
}

public class PersonComparer: IEqualityComparer<Person>{

  public bool Equals(Person p1, Person p2){
    return (p1.Name == p2.Name);
  }

  public int GetHashCode(Person p){
    return p.Name.GetHashCode();
  }
}

public class NewPersonComparer: IComparer<Person>{

  public int Compare(Person p1, Person p2){
    return (p1.Name.CompareTo(p2.Name));
  }
}

Here is the output of the program:

Initial map
Person: Francoi : Francoi's account holds 300 kroner
Person: Kurt : Kurt's account holds 100 kroner
Person: Maria : Maria's account holds 200 kroner

Kurt's account holds 100 kroner

bankMap[p1] = ba4;
Person: Francoi : Francoi's account holds 300 kroner
Person: Kurt : Unknown's account holds 0 kroner
Person: Maria : Maria's account holds 200 kroner

ba4.Deposit(400);  bankMap[new Person("Maria")] = ba4;
Person: Francoi : Francoi's account holds 300 kroner
Person: Kurt : Unknown's account holds 400 kroner
Person: Maria : Unknown's account holds 400 kroner

Account: Unknown's account holds 400 kroner. Boolean result True
Account: . Boolean result False

bankMap.Remove(p1);
Person: Francoi : Francoi's account holds 300 kroner
Person: Maria : Unknown's account holds 400 kroner

bankMap.Remove(new Person("Francoi"));
Person: Maria : Unknown's account holds 400 kroner

It should noticed that the entries in the sorted map are ordered by the persons name. This was not the case in the version of program, which relied on Dictionary<Person,BankAccount>.