When we program, one of the most-used features is data collections, whether these are from a database, from an external service, or created by ourselves. For example, imagine we have a list of employees or students in a school.
In this tutorial we’ll see how to work with this type of data. We don’t create a variable for each employee or student; instead, we create a data structure called a collection. These collections can be arrays
or Lists
.
1 - What is an Array?
An array is a type that allows us to store a collection of data of a desired type. These types can be both primitive and types that we have created ourselves.
Another feature of arrays is that they do not have a size limit and can contain as many records as we want, as long as there is enough memory on the computer. But the important thing is that the compiler won’t set a limit for us.
Finally, arrays are immutable, which means that once we initialize them, they do not change. For example, we cannot add or remove elements from an array.
1.1 - Declaring an Array
To declare an array, we must first specify the data type—whether primitive or custom. Then, we use square brackets []
to indicate that it is an array, and when we declare it, we specify the size the array will have.
int[] arrayEnteros = new int[5];
This would be the graphical representation of the code:
1.2 - Assigning values to array elements
Once we have our array initialized, it is "empty," so we need to assign values. To do this, we access the position in the array by index, which, in programming, always starts at position 0. The last element will be at the position (size - 1), in this case, 4.
arrayEnteros[0] = 25;
arrayEnteros[1] = 27;
arrayEnteros[2] = 25;
arrayEnteros[3] = 29;
arrayEnteros[4] = 20;
In this way, we assign values to the elements of the array, as you can see, we access by position. This would be the representation for each line of code:
As we saw in the video about variables and operators, in this case we can also initialize arrays when we declare them, as follows:
int[] arrayEnteros = { 25, 27, 25, 29, 20 }
This produces exactly the same result as the previous example. But notice we don’t specify the size explicitly; it's inferred from the number of parameters we provide.
1.3 - Working with the array
As mentioned earlier, arrays are immutable, which means we cannot modify them, but that does not prevent us from working with them.
Usually when we have a collection, whether lists or arrays, we work with the data both as a whole and individually. To work with them individually, we need to access each element by its index.
We commonly access records one by one using a for loop like this:
for(int i = 0; i < arrayEnteros.Length; i++){
Console.WriteLine($"The number is: {arrayEnteros[i]}")
}
As we see, in the loop to set the second parameter and know how many iterations to execute, we use a built-in function of arrays, Array.Length
.
Like Array.Length
, the type itself comes with a wide variety of methods we can use if we need them.
Array.Contains(element)
ReturnsTrue
orFalse
if the element is in the array.Array.Reverse()
Returns the array in reverse order.
There are many other methods like these we’ll see as we continue.
2 - Multidimensional Array
A regular array may not always be enough for what we need; for some scenarios, we may require an array of n dimensions. That's when we use multidimensional arrays.
2.1 - Declaring a multidimensional array
Very similar to the previous case, but this time instead of creating a single list, we create a kind of table. As before, for multidimensional arrays, we must also specify the number of elements it will contain.
string[,] ciudades= new string[2, 3];
As we can see, the graphical result would look like this:
2.2 - Assigning values to elements of a multidimensional array
To access the elements of a multidimensional array, we do it exactly as we do with a normal array. The only difference is that, in this case, we need two indices.
ciudades[0, 0] = "Teruel";
ciudades[0, 1] = "Huesca";
ciudades[0, 2] = "Zaragoza";
ciudades[1, 0] = "Valencia";
ciudades[1, 1] = "castellon";
ciudades[1, 2] = "Alicante";
And the final result after entering the data into this multidimensional array:
2.3 - Working with a multidimensional array
Since we have to access by two indices, the way we loop over the array is a bit different. In this case, we need a for loop inside another for loop, and then access with both indices (ciudades[i, j]
).
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
Console.WriteLine($"The city is {ciudades[i,j]}");
}
}
3 - Jagged array
As mentioned in the previous case, we often need an array with several dimensions, but we don’t necessarily need the same number of dimensions for all elements in the array.
For a simple example, imagine we want to read from a database all the salary changes for two employees. We could use a multidimensional array, the first row for employee1 and the second for employee2.
Let’s say employee1’s salary has changed 2 times since being hired, while employee2’s salary has changed 7 times.
If we use a multidimensional array, we would need to create decimal[,] arraySueldos = new decimal[2, 7]
. In a list with 10,000 or 10 million records, this could cause terrible performance and memory problems, because for the first employee, we are reserving 4 memory spaces we’ll never use. To avoid this, we have jagged arrays.
3.1 - Declaring a jagged array
Jagged arrays are defined slightly differently, as they mix the two types we've seen: the array and the multidimensional array.
string[][] provincias= new string[3][];
This will create space for 3 arrays, each independent, to which we have to assign a size. Like this:
provincias[0] = new string[3];
provincias[1] = new string[2];
provincias[2] = new string[4];
As you can see, we access each element by index and instantiate a new array inside it. This new array determines its own size.
The graphical representation is as follows:
As you can see, there are blank spaces because that memory is unused.
3.2 - Assigning values to elements of a jagged array
To assign values, we follow the same process, which is accessing by index. The difference is that in this case, the indices are not fixed, so when reading, we’ll do it in a different way. To assign values, we do it directly, since we know, or should know, the size.
provincias[0][0] = "Huesca";
provincias[0][1] = "Zaragoza";
provincias[0][2] = "Teruel";
provincias[1][0] = "Cáceres";
provincias[1][1] = "Badajoz";
provincias[2][0] = "A Coruña";
provincias[2][1] = "Pontevedra";
provincias[2][2] = "Ourense";
provincias[2][3] = "Lugo";
The representation would be as follows:
3.3 - Working with a jagged array
In this case, the array is totally dynamic. Each record has a different size, so to loop through it, we must check the size of each record, as we saw earlier using .Length.
for (int i = 0; i < provincias.Length; i++)
{
System.Console.Write($"registro ({i}): ", i);
for (int j = 0; j < provincias[i].Length; j++)
{
System.Console.Write("{0}{1}", provincias[i][j], j == (provincias[i].Length - 1) ? "" : " ");
}
System.Console.WriteLine();
}
//Result
registro (1):
Hueca Zaragoza Teruel
registro (2):
Cáceres Badajoz
registro (3):
A Coruña Pontevedra, ourense Lugo
As a final note, I’ll mention that you can mix multidimensional arrays with jagged arrays, but I honestly don’t recommend it. There are better ways to solve the problem, and they are rarely used in the professional world.
4 - Lists or List<T>
Now let’s move away from arrays and on to one of the most useful elements in C#: lists (or List<T>
). This data type is used so often because of its ease of use and its great functionality.
List<T>
is a data type, similar to array
, but in this case, they are mutable, which means that we can add or remove elements whenever we want.
Another very important fact about lists is that they implement IEnumerable<T>
, which is an interface that allows LINQ (Language Integrated Query), that we will see in this post. For this reason, lists are central to most of our applications.
4.1 - Creating a list
When creating a list, unlike arrays, we don’t use an index, because lists are mutable and don’t have a predefined size at initialization. To replicate the earlier example, to create a string list, you do it like this:
List<string> provincias = new List<string>();
As you see, the T
in List<T>
is the data type you want to use. This type can again be primitive or non-primitive.
4.2 - Adding elements to a list
As we mentioned before, we don’t access by index anymore, so to add elements, we do it more dynamically with the .Add(T)
method, to which we pass the data type that our list holds, in this case, string
.
provincias.Add("Teruel");
And if we have a list and want to add it to another list (for example, we’re listing all the provinces and first listing them by region), we can add a list into another list using .AddRange(List<T>)
:
aragon.Add("Huesca");
aragon.Add("Zaragoza");
aragon.Add("Teruel");
provincias.AddRange(aragon);
As you see in the example, we pass in the aragon list as a parameter.
4.3 - Working with a list
To work with a list, we can use any of the many methods the compiler provides. Here, we'll just see a few as examples.
First, let’s see how to iterate through a list, using a foreach
loop:
foreach (string provincia in provincias){
Console.WriteLine($"The province is {provincia}");
}
Other useful methods include:
lista.ToArray()
; converts the list into an array.lista.Count
; returns an integer with the number of elements in the list.lista.First()
; returns the first element.lista.Last()
; returns the last element.lista.Clear()
; empties or removes all elements in the list.
5 - LINQ
First of all, note that what we’ll see is a small introduction to the LINQ
language; covering everything would take hundreds of tutorials.
5.1 - What is LINQ
LINQ is a database query language—or at least, that was its original intention. As LINQ was being developed, the creators realized that a List<T> is essentially the results of a database query, so why not leverage this and use it in our code, not just to query but also to filter?
5.2 - How to use LINQ
Using LINQ in your code is very simple; you just need to use a type that extends from IEnumerable<T>
, such as LIST<T>.
To use it, we write: list.Where(condition)
For the "condition," you specify the element you’re working on. Commonly, I use the letter a, but many people use the initial of the iterated element, in this case (example: provinces) p.
In our example provincias.Where(p => p)
with p=>p
we specify where the query will run, iterating over each element of the list.
To add conditions to the query, we can use all the conditions available for those types; for string, we can use the .Contains()
method, which returns true or false if the element to verify contains the value passed as a parameter.
Then we go through the results, printing each record:
provincias.Add("Huesca");
provincias.Add("Zaragoza");
provincias.Add("Teruel");
IEnumerable<string> provinciasFiltradas = provincias.Where(p => p.Contains("e"));
foreach(string provincia in provinciasFiltradas){
Console.WriteLine(provincia);
}
In this scenario, it prints both Huesca and Teruel, as both contain the letter e (lowercase).
If there is any problem you can add a comment bellow or contact me in the website's contact form