Skip to content

Examples: RankedDictionary

Kasey O edited this page Oct 12, 2017 · 1 revision

This page contains several examples showing usage of the RankedDictionary class. Each example is a complete C# program with output included as comments. For complete documentation on the Kaos.Collections namespace including this class, see:

https://kaosborn.github.io/help/KaosCollections/


The first example of the RankedDictionary class shows some basic operations.

using System;
using System.Collections.Generic;
using Kaos.Collections;

namespace ExampleApp
{
    class RdExample01
    {
        static void Main()
        {
            // ISO 3166-1 country codes:
            var cc = new RankedDictionary<string,string>();

            cc.Add ("TO", "Tonga");
            cc.Add ("DD", "German Democratic Republic");
            cc.Add ("CH", "Switzerland");
            cc.Add ("RU", "Burundi");

            // The Add method throws an exception if the new key is
            // already in the dictionary.
            try
            {
                cc.Add ("DD", "East Germany");
            }
            catch (ArgumentException)
            {
                Console.WriteLine ("An element with Key = 'DD' already exists.");
            }

            // The Item property is another name for the indexer,
            // so you can omit its name when accessing elements.
            Console.WriteLine ("For key = 'CH', value = {0}.", cc["CH"]);

            // The indexer can be used to change the value associated with a key.
            cc["RU"] = "Russian Federation";
            Console.WriteLine ("For key = 'RU', value = {0}.", cc["RU"]);

            // If a key does not exist, setting the indexer for that key
            // adds a new key/value pair.
            cc["SS"] = "South Sudan";

            // The indexer throws an exception if the supplied key is
            // not in the dictionary.
            try
            {
                Console.WriteLine ("For key = 'ZZ', value = {0}.", cc["ZZ"]);
            }
            catch (KeyNotFoundException)
            {
                Console.WriteLine ("Key = 'ZZ' is not found.");
            }

            // When a program often has to try keys that are usually not in the
            // dictionary, TryGetValue can be a more efficient way to get values.
            string value = "";
            if (cc.TryGetValue ("ZZ", out value))
                Console.WriteLine ("For key = 'ZZ', value = {0}.", value);
            else
                Console.WriteLine ("Key = 'ZZ' is not found.");

            // ContainsKey can be used to test keys before inserting them.
            if (! cc.ContainsKey ("GG"))
            {
                cc.Add ("GG", "Guernsey");
                Console.WriteLine ("Value added for key = 'GG': {0}", cc["GG"]);
            }

            // When you use foreach to enumerate dictionary elements,
            // the elements are retrieved as KeyValuePair instances.
            Console.WriteLine();
            foreach (KeyValuePair<string,string> pair in cc)
                Console.WriteLine ("Key = {0}, Value = {1}", pair.Key, pair.Value);

            // To get the values alone, use the Values property.
            RankedDictionary<string,string>.ValueCollection vals = cc.Values;

            // The elements of the ValueCollection are strongly typed
            // with the type that was specified for dictionary values.
            Console.WriteLine();
            foreach(string val in vals)
                Console.WriteLine ("Value = {0}", val);

            // To get the keys alone, use the Keys property.
            RankedDictionary<string,string>.KeyCollection keys = cc.Keys;

            // The elements of the KeyCollection are strongly typed
            // with the type that was specified for dictionary keys.
            Console.WriteLine();
            foreach (string key in keys)
                Console.WriteLine("Key = {0}", key);

            // Use the Remove method to remove a key/value pair.
            Console.WriteLine ("\nRemoving 'DD'.");
            cc.Remove ("DD");

            Console.WriteLine ("\nChecking if 'DD' exists:");
            if (! cc.ContainsKey ("DD"))
                Console.WriteLine ("  Key 'DD' not found.");
        }

        /* Output:

        An element with Key = 'DD' already exists.
        For key = 'CH', value = Switzerland.
        For key = 'RU', value = Russian Federation.
        Key = 'ZZ' is not found.
        Key = 'ZZ' is not found.
        Value added for key = 'GG': Guernsey

        Key = CH, Value = Switzerland
        Key = DD, Value = German Democratic Republic
        Key = GG, Value = Guernsey
        Key = RU, Value = Russian Federation
        Key = SS, Value = South Sudan
        Key = TO, Value = Tonga

        Value = Switzerland
        Value = German Democratic Republic
        Value = Guernsey
        Value = Russian Federation
        Value = South Sudan
        Value = Tonga

        Key = CH
        Key = DD
        Key = GG
        Key = RU
        Key = SS
        Key = TO

        Removing 'DD'.

        Checking if 'DD' exists:
          Key 'DD' not found.

        */
    }
}

The next example shows enumeration of a dictionary's subcollections.

using System;
using Kaos.Collections;

namespace ExampleApp
{
    class RdExample02
    {
        static void Main()
        {
            var dary = new RankedDictionary<int,int>()
            { [36] = 360, [12] = 120 };

            Console.WriteLine ("Keys:");
            foreach (var key in dary.Keys)
                Console.WriteLine (key);

            Console.WriteLine ("\nValues:");
            foreach (var val in dary.Values)
                Console.WriteLine (val);
        }

        /* Output:

        Keys:
        12
        36

        Values:
        120
        360

        */
    }
}

The next example demonstrates LINQ usage and range queries against a dictionary:

using System;
using System.Linq;
using System.Collections.Generic;
using Kaos.Collections;

namespace ExampleApp
{
    class RdExample03
    {
        static void Main()
        {
            var towns = new RankedDictionary<string,int>();

            // Load sample data.
            towns.Add ("Albany", 43600);
            towns.Add ("Bandon", 2960);
            towns.Add ("Corvallis", 54462);
            towns.Add ("Damascus", 10539);
            towns.Add ("Elkton", 195);
            towns.Add ("Florence", 8466);
            towns.Add ("Glide", 1795);
            towns.Add ("Jacksonville", 2235);
            towns.Add ("Lebanon", 13140);
            towns.Add ("Lookingglass", 855);
            towns.Add ("Medford", 75180);
            towns.Add ("Powers", 689);
            towns.Add ("Riddle", 1020);
            towns.Add ("Roseburg", 20480);
            towns.Add ("Scio", 710);
            towns.Add ("Talent", 6066);
            towns.Add ("Umatilla", 6906);
            towns.Add ("Winston", 5379);
            towns.Add ("Yamhill", 820);

            // Here's a typical LINQ-To-Objects operation.
            double avg = towns.Average (x => x.Value);
            Console.WriteLine ("Average population of all towns = {0:f0}", avg);

            // Lambda expression
            IEnumerable<KeyValuePair<string,int>> r1 = towns.Where (t => t.Key.CompareTo ("E") < 0);

            Console.WriteLine ("\nTowns A-D:");
            foreach (KeyValuePair<string,int> e in r1)
                Console.WriteLine (e.Key);

            // LINQ range: O(n)
            IEnumerable<KeyValuePair<string,int>> r2 = towns.SkipWhile (t => t.Key.CompareTo ("E") < 0).TakeWhile (t => t.Key.CompareTo ("J") < 0);

            Console.WriteLine ("\nTowns E-G:");
            foreach (KeyValuePair<string,int> e in r2)
                Console.WriteLine (e.Key);

            //
            // Use the ElementsBetween iterator to query range.
            // Unlike LINQ SkipWhile and TakeWhile, this will perform an optimized (partial scan) lookup.
            //

            // BtreeDictionary range operator: O(log n)
            IEnumerable<KeyValuePair<string,int>> r3 = towns.ElementsBetween ("K", "M");

            Console.WriteLine ("\nTowns K-L:");
            foreach (KeyValuePair<string,int> town in r3)
                Console.WriteLine (town.Key);

            // Range operator without upper limit: O(log n)
            IEnumerable<KeyValuePair<string,int>> r4 = towns.ElementsFrom ("M");

            Console.WriteLine ("\nTowns M-R:");
            foreach (KeyValuePair<string,int> town in r4)
                // This avoids the issue in the last example where a town named "M" would be included.
                if (town.Key.CompareTo ("S") >= 0)
                    break;
                else
                    Console.WriteLine (town.Key);

            // Range operator without upper limit: O(log n)
            IEnumerable<KeyValuePair<string,int>> r5 = towns.ElementsFrom ("T");

            Console.WriteLine ("\nTowns T-Z:");
            foreach (KeyValuePair<string,int> town in r5)
                Console.WriteLine (town.Key);
        }

        /* Output:

        Average population of all towns = 13447

        Towns A-D:
        Albany
        Bandon
        Corvallis
        Damascus

        Towns E-G:
        Elkton
        Florence
        Glide

        Towns K-L:
        Lebanon
        Lookingglass

        Towns M-R:
        Medford
        Powers
        Riddle
        Roseburg

        Towns T-Z:
        Talent
        Umatilla
        Winston
        Yamhill

         */
    }
}

The next example shows usage of custom comparers.

using System;
using Kaos.Collections;

namespace ExampleApp
{
    class RdExample04
    {
        static void Main()
        {
            var dary1 = new RankedDictionary<string,int> (StringComparer.InvariantCultureIgnoreCase);
            dary1.Add ("AAA", 0);
            dary1.Add ("bbb", 1);
            dary1.Add ("CCC", 2);
            dary1.Add ("ddd", 3);

            Console.WriteLine ("Comparer is case insensitive:");
            foreach (System.Collections.Generic.KeyValuePair<string,int> pair in dary1)
                Console.WriteLine (pair.Key);
            Console.WriteLine();

            var dary2 = new RankedDictionary<string,int> (StringComparer.Ordinal);
            dary2.Add ("AAA", 0);
            dary2.Add ("bbb", 2);
            dary2.Add ("CCC", 1);
            dary2.Add ("ddd", 3);

            Console.WriteLine ("Comparer is case sensitive:");
            foreach (System.Collections.Generic.KeyValuePair<string,int> pair in dary2)
                Console.WriteLine (pair.Key);
        }

        /* Output:

        Comparer is case insensitive:
        AAA
        bbb
        CCC
        ddd

        Comparer is case sensitive:
        AAA
        CCC
        bbb
        ddd

        */
    }
}

The next example shows using a BinaryFormatter to serialize a dictionary to a file stream and read it back.

using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using Kaos.Collections;

namespace ExampleApp
{
    [Serializable]
    public class PersonComparer : Comparer<Person>
    {
        public override int Compare (Person x, Person y)
        { return x==null? (y==null? 0 : -1) : (y==null? 1 : String.Compare (x.ToString(), y.ToString())); }
    }

    [Serializable]
    public class Person : ISerializable
    {
        public string First { get; private set; }
        public string Last { get; private set; }

        public Person (string first, string last)
        { this.First = first; this.Last = last; }

        protected Person (SerializationInfo info, StreamingContext context)
        {
            this.First = (string) info.GetValue ("First", typeof (String));
            this.Last = (string) info.GetValue ("Last", typeof (String));
        }

        public virtual void GetObjectData (SerializationInfo info, StreamingContext context)
        {
            info.AddValue ("First", First, typeof (String));
            info.AddValue ("Last", Last, typeof (String));
        }

        public override string ToString() => Last + ", " + First;
    }


    class RdExample05
    {
        static void Main()
        {
            IFormatter formatter = new BinaryFormatter();
            var set1 = new RankedDictionary<Person,string> (new PersonComparer());

            set1.Add (new Person ("Hugh", "Mann"), "B+");
            set1.Add (new Person ("Hammond", "Egger"), "C-");

            SerializePersons ("Persons.bin", set1, formatter);
            Console.WriteLine ("Wrote " + set1.Count + " key/value pairs.");
            Console.WriteLine ();

            RankedDictionary<Person,string> set2 = DeserializePersons ("Persons.bin", formatter);
            Console.WriteLine ("Read back:");

            foreach (var kv in set2)
                Console.WriteLine (kv);
        }

        public static void SerializePersons (string fn, RankedDictionary<Person,string> set, IFormatter formatter)
        {
            using (var fs = new FileStream (fn, FileMode.Create))
            { formatter.Serialize (fs, set); }
        }

        static RankedDictionary<Person,string> DeserializePersons (string fn, IFormatter formatter)
        {
            using (var fs = new FileStream (fn, FileMode.Open))
            { return (RankedDictionary<Person,string>) formatter.Deserialize (fs); }
        }

        /* Output:

        Wrote 2 key/value pairs.

        Read back:
        [Egger, Hammond, C-]
        [Mann, Hugh, B+]

        */
    }
}
Clone this wiki locally