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.
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
:
Getting back to your weekly coffee management: now that the array is created, you can perform two operations on it:
Access a value at a given index.
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.
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:
Declare a variable using the
IList
type interface. That means you can assign any object to the variable that puts in place theIList
interface, including theList
class.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:
The declaration takes place before the
=
assignment operator. First, you have the type, which isList
. In this example, we will only store whole numbers.The actual creation takes place with the
new List<int>()
expression. The initialized object is assigned themyList
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]
The first statement creates an empty list named
myList
.You then add a first element with the
mylist.Add(7)
statement.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:
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:
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:
The main difference, compared to lists and set, is that you parameterize your dictionary with two elements, using the <string, int> syntax.
string
is the type for the key.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 themyDictionary
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."
You can add a value by calling the
Add()
method with two arguments: the key and the value.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.