top of page

C# List

Data management is a fundamental aspect of programming, and it often involves dealing with collections of objects. One versatile and commonly used collection type is the List. In this article, we will explore the List data structure in C#, its operations, properties, and various scenarios where it proves to be a powerful tool.


Introduction to C# List

A list is a dynamic data structure that allows you to store and manipulate collections of objects. It provides flexibility and convenience, allowing you to easily add, remove, access, and modify elements within the collection. Compared to arrays, lists offer dynamic resizing, which means they can grow or shrink as needed without requiring manual memory management.


The List class is part of the System.Collections.Generic namespace, and provides a rich set of methods and properties for manipulating and accessing elements. With Lists, you can add, remove, insert, search, sort, and iterate over elements effortlessly.


To create a list in C#, you can use the List<T> class, where T represents the type of objects you want to store in the list. For example, let's create a list of strings using the List<T> class and the collection initializer syntax:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<string> fruits = new List<string>();

        // Add fruits to the list
        fruits.Add("Apple");
        fruits.Add("Banana");
        fruits.Add("Orange");
        fruits.Add("Grapes");

        // Display the fruits
        Console.WriteLine("Fruit List:");
        foreach (string fruit in fruits)
        {
            Console.WriteLine(fruit);
        }
    }
}

Output:

C# List - 1

The above program creates a List<string> named fruits and adds four fruit names to it using the Add method. Then, it iterates over the list of the fruits using a foreach loop and displays each fruit name on the console.


Basic Operations

Lists in C# provide a rich set of methods for performing basic operations. Let's explore some of the commonly used methods:


1. Add:

The Add method is used to append an element to the end of a list. It increases the count of elements in the list by one. In the above section, we have created a list using Add() method.


2. Remove:

The Remove method is used to remove the first occurrence of a specified element from a list. If the element is found and removed, it shifts the remaining elements (if any) to fill the gap and decreases the count of elements in the list by one.


Here we have an example of how to remove an element from a list:

using System; 
using System.Collections.Generic;  

class Program 
{     
    static void Main()     
    {         
        // Creating a list of fruits         
        List<string> fruits = new List<string>         
        {             
            "Apple",             
            "Banana",             
            "Orange",             
            "Grapes"         
        };          
        
        // Display the original list of fruits         
        Console.WriteLine("Original list of fruits:");         
        PrintList(fruits);          
        
        // Remove an item from the list         
        Console.WriteLine("Removing 'Banana' from the list...");         
        fruits.Remove("Banana");          
        
        // Display the updated list of fruits         
        Console.WriteLine("Updated list of fruits:");         
        PrintList(fruits);     
    }      
    
    // Helper method to print the contents of a list
    static void PrintList(List<string> list)     
    {         
        foreach (string item in list)         
        {             
            Console.WriteLine(item);         
        }         
        Console.WriteLine();     
    } 
}

Output:

C# List - 2

The above program starts by creating a list of fruits. It then displays the original list of fruits. Next, it removes the item "Banana" from the list using the Remove method. Finally, it displays the updated list of fruits. The output shows the original list and the updated list after removing the "Banana" item.


3. Insert:

The Insert method allows you to insert an element at a specified index position within a list. It shifts the existing elements (if any) and increases the count of elements in the list by one.


The Insert method shifts the existing elements from the specified index onwards to the right, making room for the new element. It then inserts the specified item at the provided index position.


Consider the example that demonstrates Insert method in a list C#:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Creating a list of fruits
        List<string> fruits = new List<string>
        {
            "Apple",
            "Banana",
            "Orange",
            "Grapes"
        };

        // Display the original list of fruits
        Console.WriteLine("Original list of fruits:");
        PrintList(fruits);

        // Insert an item into the list
        Console.WriteLine("Inserting 'Mango' at index 1...");
        fruits.Insert(1, "Mango");

        // Display the updated list of fruits
        Console.WriteLine("Updated list of fruits:");
        PrintList(fruits);
    }

    // Helper method to print the contents of a list
    static void PrintList(List<string> list)
    {
        foreach (string item in list)
        {
            Console.WriteLine(item);
        }
        Console.WriteLine();
    }
}

Output:

C# List - 3

It's important to note that the index parameter should be within the valid range of the list. If the index is less than zero or greater than the count of elements in the list, an ArgumentOutOfRangeException will be thrown.


The Insert method is useful when you need to add an element at a specific position in a list, allowing you to control the order and placement of elements within the list.


4. IndexOf:

The IndexOf method allows you to find the index of the first occurrence of a specified element in a list. It returns an integer value representing the index of the element if found, or -1 if the element is not present in the list.


The IndexOf method performs a linear search through the list, comparing each element with the specified item using the default equality comparer for the element type. If a matching element is found, the method returns the index of that element in the list. If the element is not found, it returns -1.


Here's a program that demonstrates using the IndexOf method in a list in C#:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Creating a list of fruits
        List<string> fruits = new List<string>
        {
            "Apple",
            "Banana",
            "Orange",
            "Grapes"
        };

        // Display the original list of fruits
        Console.WriteLine("Original list of fruits:");
        PrintList(fruits);

        // Find the index of a specific item in the list
        Console.WriteLine("Finding the index of 'Orange'...");
        int index = fruits.IndexOf("Orange");
        Console.WriteLine("'Orange' is found at index: " + index);
    }

    // Helper method to print the contents of a list
    static void PrintList(List<string> list)
    {
        foreach (string item in list)
        {
            Console.WriteLine(item);
        }
        Console.WriteLine();
    }
}

Output:

C# List -4

The IndexOf method is useful when you need to locate the position of a specific element within a list or determine if it exists in the list at all. It allows you to access the index information for further processing or manipulation of the list.


5. Contains:

The Contains method is a member of the List<T> class that allows you to check whether a specific element exists in a list. It returns a Boolean value indicating whether the element is found or not.


The Contains method performs a linear search through the list, comparing each element with the specified item using the default equality comparer for the element type. If a matching element is found, the method returns true; otherwise, it returns false.


Consider the below example to check whether the given fruit exists or not.

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Creating a list of fruits
        List<string> fruits = new List<string>
        {
            "Apple",
            "Banana",
            "Orange",
            "Grapes"
        };

        // Display the original list of fruits
        Console.WriteLine("Original list of fruits:");
        PrintList(fruits);

        // Check if an item exists in the list
        Console.WriteLine("Checking if 'Banana' exists in the list...");
        bool exists = fruits.Contains("Banana");
        Console.WriteLine("'Banana' exists in the list: " + exists);

    }

    // Helper method to print the contents of a list
    static void PrintList(List<string> list)
    {
        foreach (string item in list)
        {
            Console.WriteLine(item);
        }
        Console.WriteLine();
    }
}

Output:

C# List - 5

The Contains method is handy when you need to quickly determine whether a specific element is present in a list before performing further operations or making decisions based on its existence.


6. Iteration:

Iteration of a list is a process of accessing each element in a list one by one to perform some operation or retrieve information. It allows you to traverse through the elements of the list and work with them individually.


There are two basic ways to iterate over a list in C#:

  1. foreach loop: This loop is commonly used to iterate over collections, such as lists. It automatically handles the iteration process and provides a clean syntax for accessing each element in the list without explicitly managing the index.

  2. for loop: You can also use a traditional for loop to iterate over a list. By using the loop variable as an index, you can access elements in the list based on their position.

Example to iterate a list using foreach:

using System; 
using System.Collections.Generic;  
class Program 
{     
    static void Main()     
    {         
        // Creating a list of fruits         
        List<string> fruits = new List<string>         
        {             
            "Apple",             
            "Banana",             
            "Orange",             
            "Grapes"         
        };          
        
        // Iteration using foreach loop         
        Console.WriteLine("Iteration using foreach loop:");         
        foreach (string fruit in fruits)         
        {             
            Console.WriteLine(fruit);         
        }             
    } 
}

Example to iterate a list using For loop

using System; 
using System.Collections.Generic;  
class Program 
{     
    static void Main()     
    {         
        // Creating a list of fruits         
        List<string> fruits = new List<string>         
        {             
            "Apple",             
            "Banana",             
            "Orange",             
            "Grapes"         
        };          
        
        // Iteration using for loop
        Console.WriteLine("\nIteration using for loop:");
        for (int i = 0; i < fruits.Count; i++)
        {
            Console.WriteLine(fruits[i]);
        }           
    } 
}

Output:

C# List - 6

Regardless of the method used, iteration allows you to perform various operations on the elements of a list, such as accessing their values, modifying them, performing calculations, or applying conditional logic. It is a fundamental concept when working with collections and enables you to process the data within the list efficiently and conveniently.


List Properties

Lists provide various properties that offer useful information about the collection. Let's discuss some important properties:


1. Count:

The Count property is a member of the List<T> class and is used to retrieve the number of elements in a list. It provides the total count or size of the list.


The Count property is of type int and is read-only, meaning you can only retrieve the count but cannot modify it directly.


Example usage of the Count property:

List<string> fruits = new List<string> { "Apple", "Banana", "Orange" };

int count = fruits.Count;
Console.WriteLine("The count of fruits is: " + count);

In the example above, the Count property is used to retrieve the number of elements in the list of fruits. The value of the Count property is stored in the count variable, which is then printed to the console. The output will be:

The count of fruits is: 3

Here, the Count property returns the value 3 because there are three elements in the list of the fruits.


The Count property is useful when you need to know the size or the number of elements in a list. It allows you to dynamically determine the length or extent of the list and can be used in various scenarios, such as looping through the list, performing validations, or displaying information about the list's size.


2. Capacity:

The Capacity property represents the total number of elements that the list can currently hold without resizing the internal data structure. It indicates the allocated memory size for the list, which can be greater than or equal to the number of elements currently present in the list.


The Capacity property is useful for understanding the underlying memory allocation of a list and can be used to optimize performance. By default, when you create a new list, it has an initial capacity of 0. However, as elements are added to the list, the capacity is automatically increased to accommodate the growing number of elements. This resizing operation can be relatively expensive in terms of performance.


To illustrate the Capacity property, consider the following example:

List<string> fruits = new List<string>();

Console.WriteLine("Initial Capacity: " + fruits.Capacity); 
// Output: 0

fruits.Add("Apple");
Console.WriteLine("Capacity after adding one element: " + fruits.Capacity); // Output: 4

fruits.Add("Banana");
Console.WriteLine("Capacity after adding two elements: " + fruits.Capacity); // Output: 4

fruits.Add("Orange");
Console.WriteLine("Capacity after adding three elements: " + fruits.Capacity); // Output: 4

fruits.Add("Mango");
Console.WriteLine("Capacity after adding four elements: " + fruits.Capacity); // Output: 4

fruits.Add("Pineapple");
Console.WriteLine("Capacity after adding five elements: " + fruits.Capacity); // Output: 8

In the example above, a new list of fruits is created with an initial capacity of 0. As elements are added to the list using the Add method, the capacity is automatically adjusted:

  • Initially, when no elements are present, the capacity is 0.

  • After adding the first element, the capacity increases to 4 because the list automatically reallocates memory to accommodate the new element.

  • When the second and third elements are added, the capacity remains 4 since it is sufficient to hold the current elements.

  • However, when the fourth element is added, the capacity remains 4 again because the list has reached its current capacity and needs to allocate more memory.

  • Upon adding the fifth element, the capacity increases to 8 as the list adjusts to accommodate the growing number of elements.

The Capacity property allows you to monitor and manage the memory allocation of a list. If you know the approximate number of elements you will be adding to the list in advance, you can improve performance by setting the initial capacity explicitly using the Capacity property or by using the constructor that accepts an initial capacity parameter. This can help minimize the number of resizing operations performed by the list and optimize memory usage.


3. IsReadOnly:

The IsReadOnly property allows you to determine whether a list is read-only or can be modified. It returns a Boolean value indicating whether the list is read-only (true) or not (false).


The IsReadOnly property provides a convenient way to check if a list is immutable or if modifications are allowed. A read-only list is one that cannot be changed after its initial creation, typically used when you want to ensure the integrity of the data or prevent accidental modifications.


Here's an example that demonstrates the usage of the IsReadOnly property:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Creating a read-only list of colors
        List<string> colors = new List<string> { "Red", "Green", "Blue" };
        List<string> readOnlyColors = colors.AsReadOnly();

        // Checking if the list is read-only
        Console.WriteLine("Is the 'colors' list read-only? " + colors.IsReadOnly);             // False
        Console.WriteLine("Is the 'readOnlyColors' list read-only? " + readOnlyColors.IsReadOnly); // True
        
        // Attempting to modify the read-only list
        try
        {
            readOnlyColors.Add("Yellow"); // This will throw an exception
        }
        catch (NotSupportedException ex)
        {
            Console.WriteLine("Error: " + ex.Message);
        }
    }
}

Output:

Is the 'colors' list read-only? False
Is the 'readOnlyColors' list read-only? True
Error: Collection is read-only.

In the example above, a list of colors (colors) is initially created and then transformed into a read-only list using the AsReadOnly method. The IsReadOnly property is used to check the read-only status of both lists.


The output shows that the original colors list is not read-only (false), while the readOnlyColors list is read-only (true).


An attempt to add an element ("Yellow") to the read-only list (readOnlyColors) will throw a NotSupportedException because modifying a read-only list is not allowed.


The IsReadOnly property is useful when you need to determine if a list can be modified or not, enabling you to handle read-only scenarios appropriately and avoid unintended modifications.


TrimExcess:

The TrimExcess property allows you to optimize the memory usage of a list by reducing its internal capacity to match the number of elements currently stored in the list.


The TrimExcess property does not affect the elements or their order in the list. It only adjusts the internal capacity, which is the amount of memory allocated for storing the elements. By reducing the capacity to match the actual number of elements, it can help optimize memory usage, especially if the list has had a significant number of elements removed.

Example usage of the TrimExcess property:

List<string> fruits = new List<string> { "Apple", "Banana", "Orange", "Mango" };

// Add more elements to the list
fruits.Add("Grapes");
fruits.Add("Watermelon");

Console.WriteLine($"Capacity before trimming: {fruits.Capacity}");

// Trim the excess capacity
fruits.TrimExcess();

Console.WriteLine($"Capacity after trimming: {fruits.Capacity}");

In the example above, a list of fruits is created with initial elements. Then, a few more elements are added to the list. After that, the TrimExcess method is called on the list to reduce its capacity. Finally, the capacity of the list is displayed before and after trimming.


The output will be:

Capacity before trimming: 8Capacity after trimming: 6

In this example, the initial capacity of the list is automatically set to 8. However, after adding and removing elements, the actual number of elements in the list is 6. By calling TrimExcess, the capacity of the list is reduced to match the number of elements, resulting in more efficient memory usage.


It's important to note that calling TrimExcess is not always necessary, as the List<T> class automatically manages its capacity and adjusts it as needed. However, if you have removed a significant number of elements from a list and want to minimize its memory footprint, using TrimExcess can be beneficial.


Lists of Other Types

In addition to storing strings, lists in C# can hold objects of any other type. This flexibility is achieved through the use of the generic type parameter T in the List<T> class. For example, you can create lists of integers, doubles, booleans, or any other valid C# type.

List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
List<double> prices = new List<double> { 9.99, 19.99, 29.99 };
List<bool> flags = new List<bool> { true, false, true };

You can even create lists of custom classes or structs by defining your own types. Here's an example using a custom class:

class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

List<Person> people = new List<Person>
{
    new Person { Name = "Alice", Age = 25 },
    new Person { Name = "Bob", Age = 30 },
    new Person { Name = "Charlie", Age = 35 }
};

In the above code, we create a list of Person objects and initialize it with three instances of the Person class.


Conclusion

The C# List is a powerful data structure that offers dynamic resizing, easy manipulation, and a wide range of methods for working with collections. By understanding the basic operations, list properties, searching and sorting techniques, and the ability to create lists of different types, you can effectively manage and utilize lists in your C# programs. Whether you're storing simple data types or complex custom objects, the List class provides a versatile solution for handling collections efficiently.

0 comments
bottom of page