• 20 hours
  • Easy

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 6/17/24

Manage complexity with the right collection

Imagine you are the communication manager of a fashionable theater. One of your main responsibilities is to manage the front row, which means making sure that the artists' relatives and friends, as well as other VIPs, get the best view of the show.

A child sitting in a cinema seat
A special seat for a special VIP

If all you had to do was handle two invitations for the main artist, you could use just two variables holding the guest's name. The C# code would look like this:

// Declare a variable for each guest in the front row
string frontRowGuest1;
string frontRowGuest2;

Then, when the performer gives you the information, you would assign a name to each variable. For instance, you would have:

// Assign the guest names
frontRowGuest1 = "Mary Poppins";
frontRowGuest2 = "Jane Banks";

If the front row has 30 seats, wouldn't it be easier if you could use just one variable that would contain all that information?

Lucky you! C# offers a data structure capable of holding a fixed number of values of a single type. This structure is called an array. Let's see when and how to use one.

Use an array to store a fixed number of elements

An array is a numerically ordered list of same type elements. Each element is associated with a number called an index. Indexing starts with 0 (not 1!), meaning that the first element is associated with an index 0, the second with 1, etc.

Declaring an array uses the same syntax as for any variable. You provide:

The type of the elements the array will contain, followed by [].
The variable name, which clearly expresses the intent of the array.

For instance, to store the number of cups of coffee you drink each day of the week, you can declare an array of integers with the following syntax:

// Declare the variable
int[] cupsOfCoffeePerDayOfTheWeek;

Then create the actual array with a length of seven (How many days are there in a week?) and initialize the array with it:

// Create the array and assign it to the variable
cupsOfCoffeePerDayOfTheWeek = new int[7];

When the array is created, each element is initialized with the default value of the type of the array. In the case of an int array, that means 0.

You can also declare and create an array at the same time. Here is what you would do to declare a variable and initialize it directly with a new array of three int:

Declare a variable and create an array in one statement
Declare a variable and create an array in one statement

Getting back to your weekly coffee management: now that the array is created, you can perform two operations on it:

  1. Access a value at a given index.

  2. Set a new value at a given index.

In both cases, you use the name of the variable followed by [, the value of the index, then ].

For instance, if you drink three coffees on the fifth day of the week, you can write:

// Assign the value 3 to the fifth day of the week
// That's index 4, since the first index is 0
cupsOfCoffeePerDayOfTheWeek[4] = 3;

To print the number of coffees you drink on the first day of the week, you can write the following statement:

//Print the number of coffees on the first day of the week
Console.WriteLine(cupsOfCoffeePerDayOfTheWeek[0]);

Finally, if you want to set all the values at the same time, you can either:

  • Set all the values when you create the array.

  • Use a loop that sets each value, one by one.

Loops will be covered in the next part of the course. For now, let's create a new array and assign it to the cupsOfCoffeePerDayOfTheWeek variable:

// Create a new array with all the values and assign it to our variable
cupsOfCoffeePerDayOfTheWeek = new int[] {6,2,3,7,3,4,1};
Try it out for yourself!

What about the theater front row? Well, you just need to create an array of String with the number of seats your front row contains. You can either add all your guests at the time of creation, or add them individually using the[] syntax.

Practice arrays with the following interactive exercise:

To access the exercise, click this link.

If you want to take it a step further and manage all the rows in your theater, you would use multidimensional arrays. Let's say your theater contains 30 rows of 12 seats. Here is how you can create an array and assign a value to the sixth seat in the tenth row:

// Create a multidimensional array to manage all the rows of a theater
string[,] myTheatreSeats = new string[30,12];

// Row 10, Seat 6. Don't forget that the index starts at 0!
myTheatreSeats[9,5] = "James Logan";

Arrays are mutable, efficient, and great if you manage a fixed number of elements.

What does mutable mean?

Simple stated, mutable objects can be modified after they're created whereas immutable objects cannot. For example, a string is immutable.

string name = "john";
name = "bob";
Console.WriteLine(name); //-> bob

 The answer to the above example is "bob." 

Wait, you said string is immutable? But, you were able to change the value of name.

Yes, but the compiler created a new string object for name, and then assigned "bob" to it. See what happens when you try to modify the  string:

string name = "john";

// Capitalize the first character
name[0] = "J"; //-> ERROR - Property or indexer 'string.this[int]' cannot be assigned to -- it is read only

Console.WriteLine(name);

You get an error, "Property or indexer 'string.this[int]' cannot be assigned to -- it is read only". This is because string is immutable; it cannot change. 

As stated earlier, arrays are mutable.

int[] myArray = new int[] { 1,2,3,4,5,6 };
myArray[4] = 7;
Console.WriteLine(myArray[4]); //-> 7

Because an array is mutable, you are able to modify it without having the compiler create a new object array.

As you learn C#, you will begin to see the importance of understanding mutable and immutable objects because these two have an effect on performance and memory management of your applications.

Use lists when the number of elements is not fixed

Arrays are well and good, but they have limitations:

  • They have a fixed size.

  • You can only change the existing values.

Let's say you wanted to list animals in order of their cuteness, and you start off with a small array of four items: fox, owl, koala, and otter. Now, let's say you want to add a squirrel and put it between the fox and the owl.

A squirrel climbing a tree trunk.
This one deserves a spot at the top

With an array, you can't insert an additional item, you can only replace items. You also cannot add (in programming speak: append) your squirrel to the end of the list. To accommodate it, you'd have to create a whole new array with five spots instead of four. Then you'd have to add all your elements again by hand. That sounds pretty long and boring, right?

That's where an ordered list comes in! As they are mutable, you can modify the contents and the number of a given collection of elements. After arrays, this feels magical! ✨

Among other things, lists allow you to:

  • Access each element by its index.

  • Append (add) a new element to the end.

  • Insert a new element at a specific index.

  • Remove an element at a specific index.

Very useful! In C#, there are several classes that use lists. You could even create your own! It's important that the class you choose uses the IList interface.

In the rest of this chapter, we will use the List class, which is the most common. Let's see how this works in practice!

Create a list and add elements

To create a list, you need to:

  1. Declare a variable using the IList type interface. That means you can assign any object to the variable that puts in place the IList interface, including the List class.

  2. Initialize the variable with an expression starting with the new keyword that creates an instance of the list class.

This can be done in one line with the following syntax:

List declaration and initialization
List declaration and initialization
  1. The declaration takes place before the = assignment operator. First, you have the type, which is List. In this example, we will only store whole numbers.

  2. The actual creation takes place with the new List<int>() expression. The initialized object is assigned the myList variable.

But what about the stuff we want to put in our list?

Great question! To put in elements, you can add them all at once:

IList<int> myList = new List<int>{1, 2, 3, 4, 5, 6};

Or, add them individually:

IList<int> myList = new List<int>();
myList.Add(7); //-> [7]
myList.Add(5); //-> [7,5]
  1. The first statement creates an empty list named myList.

  2. You then add a first element with the mylist.Add(7) statement.

  3. Finally, the myList.Add(5) statement creates an instance of the integer class with a value of 5 and adds it to the list at index 1.

Now, what's going on with that .Add()? In C#, adding, modifying, or removing elements requires using something called a method, and you guessed it, .Add() is one such method! At this point, all you need to know about methods is that they let you do things. 😎

For the IList interface, there are three methods that are put in place by the List class that come in handy:

  • Add - To add a new element at the end of an array. Here you need to provide a new element.

  • Insert - You can also insert a new element at a given position by specifying the index before the value. For instance, myList.Insert(1,12) will insert an integer with value 12 at position 1 and move the existing value at position 2, and so on.

  • RemoveAt - To delete an existing element at a specific index. Here you need to provide the index of element you wish to remove. If you no longer need the first element, you can remove it from position 0. That will shift the original second element from position 1 to position 0, the third from position 2 to position 1, and so on.

Now, what does that look like? Here's the C# syntax for the above:

IList<int> myList = new List<int>(); // -> []
myList.Add(7); // -> [7]
myList.Add(5); //-> [7, 5]
myList.Insert(1,12); //-> [7, 12, 5]
myList.RemoveAt(1); // removed 12 -> [7, 5]

Let's break this down, shall we?

  • You can see the same operation from before: adding 7, then 5 to the list.

  • Then you insert 12 at index 1. The existing value at index 1 is moved to index 2.

  • Finally, with .RemoveAt(), you're asking your list to remove whatever value is found at index 1. That means you're asking it to get rid of 12.

This leaves you with your final list containing two integers: 7 and 5. Imagine doing that with fixed-sized arrays!

Keep track of the number of elements in your list

There is a very important property to use with a list; Count, which allows you to get the number of elements in a list:

IList<int> myList = new List<int>();
myList.Add(1); // ->[1]
myList.Add(2); //-> [1,2]
Console.WriteLine(myList.Count); // -> 2

This makes it a lot easier to keep track of the placement of elements in your list.

The Count property is used a lot, notably when you need to loop over a list. We'll get to this in Chapter 3 of the next part.

Try it out for yourself!

Ready to get started? To access the exercise, click this link.

Unordered collection - sets

A set is a collection of unordered unique elements. You'd use them when you don't care about the order - like a list of ingredients for a recipe. 🥑🌶🥕🌽🍅🍳

Declaring sets

Like with lists, C# has different classes to manage sets. We will focus on the most commonly used, the HashSet.

Let's see the C# code:

Declaring a set
Declaring a set

As you can see, it's pretty similar to working with a List. You first declare the variable with the ISet interface, and initialize it with an instance of the concrete HashSet class.

Manipulating set elements

Here are the frequently used operations you can use with sets:

  • Add a new element with a new key.

  • Remove an element for a specific key.

  • Count the number of elements in the set.

What about accessing an element?

Since sets are unordered collections, there's no simple way to point at particular elements - at least not like the ones you've seen so far. There are ways of doing this, but you'll learn more about them as you expand your knowledge of programming.

To add a new element, use Add():

ISet<string> ingredients = new HashSet<string>();
ingredients.Add("eggs");
ingredients.Add("sugar");
ingredients.Add("butter");
ingredients.Add("salt");

Since sets are unordered, using append or inserting elements at a specific point isn't necessary. All you do is add!

To remove an element, you use Remove():

ISet<string> ingredients = new HashSet<string>();
ingredients.Add("salt"); // adds salt to ingredients
ingredients.Remove("salt"); // removes salt from ingredients

The trick is that you must provide the exact element to remove. Here you're getting rid of "salt."

Sets, like lists, also use the Count property to get the number of elements in a set:

Console.WriteLine(ingredients.Count);
Try it out for yourself!

Ready to get started? To access the exercise, click this link.

Dictionaries

To recap from the video, a dictionary is a list of elements organized by a key. This key is a specific term you look up to find its definition or its value. This is called a KEY <> VALUE association.

For example, if you need to store your friends and their ages, dictionaries are the right collection to use:

Collection of elements organized by key: Jenny 34, Livia 28, Paul 31.
Dictionary elements

All keys in a dictionary must be unique. It's like how only one person can sit on a chair at a time.

Declaring dictionaries

As for lists and sets, C# provides several classes to manipulate dictionaries. Each of these classes abides by the IDictionary interface, for which you can see the extensive documentation on Microsoft's C# tutorial website.

For this section, we will use the most common: Dictionary class. Here is the code to declare and initialize an instance of that class:

Declaring a dictionary in C#
Declaring a dictionary in C#

The main difference, compared to lists and set, is that you parameterize your dictionary with two elements, using the <string, int> syntax.

  1. string is the type for the key.

  2. int is the type for the value.

To add items to your dictionary, use the method myDictionary.Add(). In the parentheses, indicate the key first, then the value:

// my friends' ages
myDictionary.Add("Jenny", 34);
myDictionary.Add("Livia", 28);
myDictionary.Add("Paul", 31);
Console.WriteLine(myDictionary["Jenny"]); // -> 34

In the last line, we've asked the program to print out the value for the Jenny key. In this code:

  • The Console.WriteLine() method prints the result of an expression that is provided between its parenthesis.

  • The actual expression, myDictionary["Jenny"], returns the value identified by the key Jenny, that is stored in the myDictionary variable.

While using strings as keys, remember that such keys are case sensitive. For example, "Jenny" and "jenny" are two different keys that will associate with two different elements in a dictionary. For example:

myDictionary.Add("Jenny", 34);
myDictionary.Add("Livia", 28);
myDictionary.Add("Paul", 31);
myDictionary.Add("jenny", 21);
Console.WriteLine(myDictionary["Jenny"]); // -> 34
Console.WriteLine(myDictionary["jenny"]); // -> 21

To protect against such situations, use constants to specify the keys once, and then reuse them throughout the code:

// define keys as constants 
const string keyJenny = "Jenny";
const string keyLivia = "Livia";
const string keyPaul = "Paul";

// use constants as keys
myDictionary.Add(keyJenny, 34);
myDictionary.Add(keyLivia, 28);
myDictionary.Add(keyPaul, 31);

// access an element4
Console.WriteLine(myDictionary[keyJenny]); // -> 34

As you can see, you have to use the const keywords here to indicate that you need your strings to be constants and not variables. This is very useful as it guarantees that you keep your keys forever and will not lose any data by accidentally changing the key strings!

A little more about keys

While the most commonly used type is string, keys in C# can vary. For example int:

morning.Add(1, "Wake up");

Just like for simple variable types and arrays, the same rules apply to dictionaries: it always has a type that cannot be changed. All values and keys in a dictionary must be of the same type:

myDictionary.Add(keyJenny, 34);
myDictionary.Add(keyLivia, 28); // Ok
myDictionary.Add("Paul", "Designer"); // Error

Manipulating dictionary elements

Here are the frequently used operations you can do with dictionaries:

  • Access the value of an element by its key.

  • Add a new element with a new key and value.

  • Remove an element for a specific key.

Let's imagine a dictionary of people's names and their jobs, called "professions."

  1. You can add a value by calling the Add() method with two arguments: the key and the value.

  2. To access a value, specify the key in brackets [] following the dictionary name. This is called the indexer.

Let's check it out:

professions.Add("Jenny", "Business owner");
Console.WriteLine(professions["Jenny"]); // -> Business Owner

You can also modify an element by reusing an existing key with the indexer:

professions.Add("Jenny", "Business owner");
Console.WriteLine(professions["Jenny"]); // -> Business Owner
professions["Jenny"] = "Developer";
Console.WriteLine(professions["Jenny"]); // -> Developer

Finally, to remove an element you can use a Remove() method with the key of the element you want to go:

professions.Remove("Jenny");

Counting elements

Dictionaries, like lists and sets, also use the Count property to get the number of elements in dictionaries:

Console.WriteLine(professions.Count);
Try it out for yourself!

Ready to get started? To access the exercise, click this link.

Let's recap!

In this chapter, you've learned the basics of working with containers that store multiple elements of a given data type:

  • Arrays (fixed-size containers): Elements of an array are indexed from 0 up and can be accessed using that index. The number of elements cannot be changed.

  • Lists (ordered lists): Elements of a list behave like an array. The number of elements can evolve by adding and removing elements.

  • Sets (unordered lists): Elements of a set are stored without a particular order and can be accessed by enumerating them.

  • Dictionaries: Elements of a dictionary are organized by key-value pairs and can be accessed using a key.

  • The most common actions performed with collections are:

    • Access an element

    • Add a new element

    • Remove an element

    • Modify an element

    • Count all elements

    • Enumerate all elements

Which of the collections you choose depends on the task at hand. As you progress with your career, you'll be able to identify the best suitable type to use.

Example of certificate of achievement
Example of certificate of achievement