We've learned a lot about arrays and how to manage the content of an array, but there other types of collections available in .NET for you to use with C#.In this module, we will learn about a few of those types and show how they can each represent an element of a card game.

Download this lesson as a Polyglot Notebook to open in Visual Studio Code, or open directly in your web browser with Binder.

Hashtable and SortedList

A Hashtable and SortedList are collections of key/value pairs that contain no duplicate keys. The Hashtable is sorted based on the hash of the keys and a SortedList is sorted based on the key value.

Let's put three cards into a SortedList and a Hashtable and see how they're sorted differently.We'll use a hand with a poker straight flush of 2, 3, 4, 5, and 6 of clubs:

//var hand = new Hashtable();
var hand = new SortedList();

// These statements add a value to the collection in the form (key, value)
hand.Add("2C", "2C");
hand.Add("3C", "3C");
hand.Add("4C", "4C");
hand.Add("5C", "5C");
hand.Add("6C", "6C");

display(hand)

Try commenting and uncommenting the definition of the deck and observe how it sorts the collection differently for each of the types. The Hashtable is not stored in the order by the raw values of the key, but by the hashed values of the key. Those hashed keys mean that it is quicker to look up those values from the Hashtable than the SortedList. Let's do a simple performance test, fetching a card from our hand of 5 cards 10 million times. This data set is so small, we need to fetch a random card millions of times in order to observe a difference in performance.

Try running this block again, and we'll choose a card from the hand based on a random rank value. Run the code for both the SortedList and the Hashtable and observe the time that it takes to select a card from the hand 10 million times.

var hand = new SortedList();
//var hand = new Hashtable();

// These statements add a value to the collection in the form (key, value)
hand.Add("2C", "2C");
hand.Add("3C", "3C");
hand.Add("4C", "4C");
hand.Add("5C", "5C");
hand.Add("6C", "6C");

var random = new Random();
for (var i=0; i<10_000_000; i++) {

? var rank = random.Next(2, 7);
? var foundCard = hand[$"{rank}C"];

}

Which one would you use to model a hand of cards?

Another key feature of the SortedList and Hashtable is that they prevent duplication of keys in their collection. Let's look at our hand of cards and try to add a card with the same key:

var hand = new SortedList();
//var hand = new Hashtable();

// These statements add a value to the collection in the form (key, value)
hand.Add("2C", "2C");
hand.Add("3C", "3C");
hand.Add("4C", "4C");
hand.Add("5C", "5C");
hand.Add("6C", "6C");

// Add a duplicate
hand.Add("2C", "7C");

Even though the value of "7C" is unique in the collection, both SortedList and Hashtable throw an error when adding a value with a key that already exists.

We've been adding cards to the collection, but we can also remove cards from the collection with the Remove method:

//var hand = new SortedList();
var hand = new Hashtable();

// These statements add a value to the collection in the form (key, value)
hand.Add("2C", "2C");
hand.Add("3C", "3C");
hand.Add("4C", "4C");
hand.Add("5C", "5C");
hand.Add("6C", "6C");

// Remove a card
hand.Remove("2C");

display(hand);

Queues

A Queue is a collection of objects stored and accessed in a first-in / first-out manner. Enqueue to add elements to the Queue and Dequeue to remove elements from the Queue. You can also Peek to inspect the oldest element in the Queue

In the scenario of building a card game, a Queue might represent the collection of cards that is being delivered to a player by the dealer. This is not their hand, but the middle collection that represents that pile of cards the dealer builds in front of the player. The first card delivered to the player is picked up first, then the second, and so forth

var myHand = new Queue();
myHand.Enqueue("2C");
myHand.Enqueue("3C");
myHand.Enqueue("4C");

myHand

Our hand contains the three cards, and they reside in the order that they arrived in our hand. We can look at several properties of the queue so that we can measure and interact with the queue properly.

We can count the number of entries in the queue:

myHand.Count

We can also peek at the first entry in the queue without removing it from the queue:

display(myHand.Peek());
display(myHand);

We can finally dequeue an entry from the queue and this will remove the first entry and return that value:

display(myHand.Dequeue());
myHand

Stacks

We've modeled a hand of cards and the process of dealing a hand of cards, but what about the deck of cards? We've previously modeled this as an array and while that worked its not entirely accurate behavior of the deck of cards. We couldn't really remove a card or add a card to the deck.

A Stack is a collection that is accessed in Last-in/First-out manner using the Push and Pop methods to add and remove items, with the Peek method available to examine the next item to be removed from the Stack.The Stack is our best representation of a deck of cards:the last card that is placed on the top of the deck is the first to be dealt to a player.

var myDeck = new Stack();

myDeck.Push("AD");
myDeck.Push("AS");
myDeck.Push("9H");
myDeck.Push("9S");
myDeck.Push("9C");

myDeck

Let's take a look at the top card of the deck using the Peek method. Yea, you really are peeking at the first card on top of the deck!

var myCard = myDeck.Peek();

myCard // The 9-Clubs is returned first because it was Pushed onto the Stack LAST

We can peek at the top card and then we can Pop that card of the top of the stack:

display(myDeck.Peek());
var thisCard = myDeck.Pop();

display(thisCard);
display(myDeck);
About Us

CSharp In the Cards is a free technical educational series produced by Jeffrey T. Fritz and available in video, text, and source code formats. In the future, we plan to have more formats available

Contact Us

An unhandled error has occurred. Reload 🗙