#1,133 – Initializing a Dictionary with a Collection Initializer

You can initialize a generic Dictionary with a collection initializer as follows:

            // Initialization with collection initializer
            Dictionary<string, int> guys = new Dictionary<string,int> {
                    {"Galileo", 1564},
                    {"Magellan", 1480},
                    {"Voltaire", 1694},
                    {"Kepler", 1571},
                    {"Keaton", 1895}
                };

            foreach (KeyValuePair<string, int> kvp in guys)
                Console.WriteLine("{0} ({1})", kvp.Key, kvp.Value);

1133-001

Advertisement

#1,132 – Using a SortedDictionary

You can use a SortedDictionary<T1,T2> instead of a Dictionary<T1,T2> when you’d like entries sorted in the dictionary by the value of their keys.  Below is an example where we count how many times each letter of the alphabet is found in a particular string.

            string someText = "One cannot think well, love well, " +
                "sleep well, if one has not dined well.";

            SortedDictionary<char, int> charCounter = new SortedDictionary<char, int>();

            foreach (char c in someText)
            {
                if (char.IsLetter(c))
                {
                    char cLower = char.ToLower(c);
                    if (!charCounter.ContainsKey(cLower))
                        charCounter.Add(cLower, 1);
                    else
                        charCounter[cLower]++;
                }
            }

            Console.WriteLine("Found {0} unique letters", charCounter.Keys.Count);

            foreach (KeyValuePair<char, int> kvp in charCounter)
                Console.WriteLine("[{0}] - {1} instances", kvp.Key, kvp.Value);

1132-001

#1,131 – Example of Using a Generic Dictionary

Below is an example of using a generic dictionary to count how many times each type of letter appears in a passage of text.  The keys are of type char (the letter found) and the values are of type int (# times found).

            string someText = "One cannot think well, love well, " +
                "sleep well, if one has not dined well.";

            Dictionary<char, int> charCounter = new Dictionary<char, int>();

            foreach (char c in someText)
            {
                if (!charCounter.ContainsKey(c))
                    charCounter.Add(c, 1);
                else
                    // charCounter[c] is of type int,
                    //   c is of type char
                    charCounter[c]++;
            }

            Console.WriteLine("Found {0} unique characters", charCounter.Keys.Count);

            foreach (KeyValuePair<char, int> kvp in charCounter)
                Console.WriteLine("[{0}] - {1} instances", kvp.Key, kvp.Value);

1131-001

#1,130 – Checking to See if a Generic Dictionary Already Contains a Key

When using a generic dictionary, you can use the square bracket syntax to retrieve the value for a specified key.  This will only work, however, if that particular key has already been added to the dictionary.  When you first create the dictionary, it contains no keys.

If you try retrieving a value for a key that doesn’t already exist in the dictionary, you’ll get a KeyNotFoundException at runtime.

1130-01

You can avoid this error by first checking to the presence of a key using the ContainsKey method of the dictionary.  If this method returns true, you can safely retrieve the value of the key using the square bracket syntax.

            Dictionary<char, int> charCounter = new Dictionary<char, int>();

            int numEs = charCounter.ContainsKey('e') ? charCounter['e'] : 0;

 

#1,129 – Generic Dictionary Basics

The generic dictionary class, System.Collections.Generic.Dictionary<TKey,TValue>, allows you to store a collection of key/value pairs, where the both the keys and the values have a particular type.

You specify types for the keys and values when you declare an instance of the dictionary, creating a constructed type.  The example below creates an instance of a dictionary that stores an integer value for each of a set of character values.

            Dictionary<char, int> charCounter = new Dictionary<char, int>();

By default, the collection contains no entries–no key/value pairs.  You add an entry using the Add method, specifying a new key to be added, along with its value.  Note that the key is of type char and the value is of type int.

            charCounter.Add('x', 12);

If a dictionary already contains a particular key, you can retrieve the value using square bracket syntax.

            int numXs = charCounter['x'];

 

#1,118 – foreach Works with Iterator Returned by yield

You can use the yield keyword in a method to implement an iterator.  The method in which it is defined returns an IEnumerable or IEnumerator.  The resulting iterator can be consumed using the foreach statement.

Below is an example of a method that returns an IEnumerable<T> which can then be iterated upon using a foreach statement.

        static IEnumerable<Dog> DogsWithKids(IEnumerable<Dog> dogList)
        {
            foreach (Dog d in dogList)
            {
                yield return d;
                yield return new Dog(d.Name + " Jr.",
                                     Math.Max(d.Age - 3, 1));
            }
        }

        static void Main(string[] args)
        {
            List<Dog> myDogs = new List<Dog>
                {
                    new Dog {Name = "Kirby", Age = 15},
                    new Dog {Name = "Ruby", Age = 2}
                };

            // Iterate through dogs w/offsprings
            foreach (Dog d in DogsWithKids(myDogs))
                Console.WriteLine(d);

            Console.ReadLine();
        }

The result is a sequence with twice as many elements as the original List<T>.

1118-001

#1,117 – foreach Requires IEnumerable Implementation

The foreach statement works on an object that implements IEnumerable<T> or IEnumerable.  It also works on an object whose type has a public GetEnumerator method that returns an IEnumerator<T> or IEnumerator.

Below, we’ve defined a new class that implements IEnumerable<T>.

    public class DogPack : IEnumerable<Dog>
    {
        private List<Dog> thePack;

        public DogPack()
        {
            thePack = new List<Dog>();
        }

        public void Add(Dog d)
        {
            thePack.Add(d);
        }

        // Remove arbitrary dog
        public void Cull()
        {
            if (thePack.Count == 0)
                return;

            if (thePack.Count == 1)
                thePack.RemoveAt(0);
            else
            {
                Random rnd1 = new Random();
                int indRemove = rnd1.Next(thePack.Count);
                thePack.RemoveAt(indRemove);
            }
        }

        // IEnumerable<T> implementation

        public IEnumerator<Dog> GetEnumerator()
        {
            return thePack.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

We can now use foreach to iterate on an instance of this class.

            DogPack pack = new DogPack();
            pack.Add(new Dog("Lassie", 8));
            pack.Add(new Dog("Shep", 12));
            pack.Add(new Dog("Kirby", 10));
            pack.Add(new Dog("Jack", 15));
            pack.Cull();

            // Who's left?
            foreach (Dog d in pack)
                Console.WriteLine(d);

1117-001

#845 – Using the Generic Queue Class

A queue is a data structure that allows adding elements at one end of the queue, through Enqueue operations, and removing elements from the other end, through Dequeue operations.

The .NET Framework includes a Queue<T> type, defined in System.Collections.Generic, that implements a queue data type.

When you declare a queue, you indicate the type of objects that the queue will contain.

            Queue<Person> peopleInLine = new Queue<Person>();

You can now add instances of Person objects to the (back of) the queue using the Enqueue method.

            // Ernest - 1st guy in line
            peopleInLine.Enqueue(new Person("Ernest", "Hemingway"));

            // Scott in line behind Ernest
            peopleInLine.Enqueue(new Person("F. Scott", "Fitzgerald"));

845-001
You can remove the object from the front of the queue using the Dequeue method.

            // Remove guy from front of line -- Ernest
            Person next = peopleInLine.Dequeue();

845-002

#844 – The Queue Data Type

A queue is a data type used to store a collection of items and which has the following properties:

  • Elements can be added to the queue
  • Elements can be removed from the queue, but only in the order in which they were added

Adding an item is known as a Enqueue operation.  Removing an item is known as a Dequeue  operation.

You can think of a queue data type as being like people standing in a line.  You can enter the line only at the back (Enqueue) and you can leave the line, but only from the front (Dequeue).

A queue is also known as a FIFO (First-In, First-Out) structure.

844-001

#843 – Using the Generic Stack Class

A stack is a data structure that allows adding elements to the top of the stack through a Push operation, or removing elements from the top of the stack through a Pop operation.

The .NET Framework includes a Stack<T> type, defined in System.Collections.Generic, that implements a stack data type.

When you declare a stack, you indicate the type of objects that the stack will contain.

            Stack<Book> pileOfBooks = new Stack<Book>();

You can now add instances of Books to the top of the stack using the Push method.

            // Push 1st book onto stack
            pileOfBooks.Push(new Book("The World According to Garp", new Person("Irving", "John")));

            // Push another.  Gatsby on "top" of stack
            pileOfBooks.Push(new Book("The Great Gatsby", new Person("Fitzgerald", "F. Scott")));

843-001
You can remove the object from the stop of the stack using the Pop method.

            // Remove book from top
            Book bookToRead = pileOfBooks.Pop();
            Console.WriteLine(bookToRead);

843-002
843-003