Data Structures in C# Part 2: Lists <T>
Tags: csharp, programming, webdev, dotnet
Published: 2023-06-02 13:20:47

## Hey There 👋🏻
In part 1 of this series, I talked about **arrays**, which are cool and provide amazing functionality, and to extend on the data structures that you the developer could use, we'll be learning the **generic lists** in C#, which is an essential data structure that any C# developer should have at their disposal.

## So, Let's begin 🚀

**What is a list in C#?**
Lists in C# are a type of the generic collections that can be used to store objects of the same data type which then can be accessed through their indexes. Well, how are they any different from arrays that we discussed in part 1 you may ask?

Good question.
The answer is pretty simple! Lists are dynamic, meaning that they could grow and shrink, whereas arrays have fixed a size which is assumed to be known by the developer in the moment of creating the array.

**How do we create a list?**
Creating a new list is pretty straightforward, let's have a look at a couple of ways:

```csharp

List<string> values = new();
List<string> values = new List<string>();
var values = new List<string>();

```

In the previous code, I showed the 3 ways in which we could declare a new list with the name **value** that will store **string** values.

> You can use whichever syntax you like, it's a subjective preference and has nothing to do with correctness or the like.

In the previous code, we declared a new list of strings, but we haven't provided it with any values. The following code block shows how values are initially added to a list immediately after declaration:

```csharp

List<string> values = new()
{
    "Value1" , "Value2" , "Value3,
};

```

In this snippet, I created the **values** list and I added 3 elements to it, elements are **comma separated**.

> NOTE: We could've done the declaration in a step, and the initialization in a separate step, but it's more convenient this way since I knew what values will be seeded in advance.

**How to access elements in a list?**
We can access elements the same way we did with **arrays**, through the index of an element, again, **lists are zero-indexed**, just like arrays.

The next code snippet prints the final value in the list:

```csharp

Console.WriteLine(values[2]);
//OUTPUT: Value3

```

To update an element, we can easily just use its index and provide it a new value, just like the following:

```csharp

values[0] = "New Value At 0";
Console.WriteLine(values[0]);
//OUTPUT: New Value At 0

```

**That simple!**


## Let's see the dynamic features of **Lists**
As I said previously, one key point that makes lists differ from arrays is their dynamic nature. Let's look at some methods and properties of the generic list so we can see its dynamism in action.

**List.Add();**: This method adds a new element to the list, the element has to of course be of the same type as the type you choose when you first create the list.

```csharp

List<int> numbers = new();

for(int i = 1; i <= 10; i++)
{
    numbers.Add(i);
}

```

The previous code creates a new list of **integers** and uses a for loop to add the numbers from 1 to 10 to our numbers list.

**List.Remove();**: This method is contrary to the first one, it removes an item from the list, let's see how we can remove an element that we added to our **numbers** list:

```csharp

numbers.Remove(5);

```

After this removal, I can use a foreach loop to print out all the numbers in the numbers list, just as follows:

```csharp

foreach(int number in numbers)
{
    Console.Write($"{number}\t");
}
//OUTPUT: 1       2       3       4       6       7       8       9       10

```

And as you can see, the **5** is missing in the sequence.

**List.Count**: This property is equivalent to **Array.Length**, it returns the number of elements in a list, it's particularly useful if you want to use a **for** loop.

**List.Capacity;**: This property **gets** or **sets** the overall number of elements that the list can hold without having to resize itself. If you create a list with one element, and you print out its capacity, you will see **4** is printed out, that means the list can now accommodate **4 elements** before it has to resize and expand itself, similarly, the capacity will be brought down if elements are being removed from the list.

> 💡**Pro Tip:** If the number of elements that will go inside the list is known beforehand, then set its capacity to that number so it improves performance. Say you want a list with only 2 items, by setting the capacity to 2, the list won't make it 4 automatically, thus gaining some bits and pieces in performance here and there, but don't worry that much about it, computers are fast enough these days to handle those small margins.


## How to **search** for an element in a list?
Assuming we're looking for the index of a particular value in our list, how do we get it? It could be done manually by looping over the elements of the list and then comparing each individual value to the target value that we want its index. However, there'a much easier way by using the `FindIndex` Method. Let's see that in code:

```csharp

List<int> numbers = new() {5 , 10 , 15 , 20 , 25};
int indexOfTen = numbers.FindIndex(index => index == 10);

Console.WriteLine($"The index of the number 10 is: {indexOfTen}");
//OUTPUT: The index of the number 10 is: 1

```

In this snippet, I created a new numbers list and initialized it with 5 values, then I declared a new variable with the name `indexOfTen`, I assigned it to the returned value from the `FindIndex()` method, for its argument, I passed a **Lambda Expression**, which is like a condition, if the condition is true, then we want to return the index of the first value that evaluated our condition to true, this thing is called a **predicate**, which is a delegate, but that's not what we're here for.

> 💡**Pro Tip:** Lists and most collections in C# couple extremely well with **LINQ**, **L**anguage **IN**tegrated **Q**uery which is a very powerful feature of C#, if you're interested in learning the basics of it, I have a full post where I provided tons of practical examples, you can find the post's link at the end of this post.

**List.Find();**: This method returns the value provided if found, otherwise, the default value of the data type that the list is storing, **0** for value types, **null** for reference types. This method is used heavily while doing **data access**, and for that reason, I want to show you a practical example that involves searching for a particular object inside a list.

For this example, I'll create a `class`, and call it Superhero with only 2 properties, an **ID** and a **Full Name**, you can see its code below:

```csharp

public class Superhero
{
    public int Id { get; set; }
    public string FullName { get; set; }
}

```

That's our class sorted, let's create a list of super heroes:

```csharp

List<Superhero> heroes = new()
{
    new Superhero {Id = 1, FullName = "Tony Stark"},
    new Superhero {Id = 2, FullName = "Peter Parker"},
    new Superhero {Id = 3, FullName = "Steve Rogers"}
};

```

I declared a list called `heroes` that stores objects of type `Superhero`, then I initialized it with 3 objects, each with their respectively unique ID. Now, I want to find if there's a hero with the ID 2, if so, I want to print out their name, let's see that in code:

```csharp

Superhero heroWithIdTwo = heroes.Find(hero => hero.Id == 2);

if (heroWithIdTwo != null)
{
    Console.WriteLine($"The hero with ID 2 is called: {heroWithIdTwo.FullName}");
//OUTPUT: The hero with ID 2 is called: Peter Parker
}

```

All I'm doing here is looking through my list of heroes, to check if there's a hero with 2 as their ID, which I know in advance that there's a hero with this ID, in a real scenario, you would want to throw an exception and catch it so that you could return some error message to the user saying that an object with the given ID doesn't exist, but that's not related to what we're learning in this series.


## 👾 And There you have it 👾
You've learned how to use the generic list in C#, which is absolutely **Brilliant**, if I could leave you with a final piece of advice, it has to be me telling you to play around with this data structure, as it's extremely powerful and used everywhere, and even though it seemed like we covered a lot in this post, we've barely scratched the surface, but still, you're ready to take what we've learned and experiment on your own, and before you go, check the LINQ post so that you get some hands on experience with a great companion for lists and most other data structures in C#.

## Bye for now 👋🏻

Learn LINQ here: 👉 https://dev.to/rasheedmozaffar/basics-of-linq-in-c-with-examples-2dgi