Skip to main content

.NET Lists

Introduction

Lists are one of the most commonly used data structures in .NET programming. Unlike arrays which have a fixed size, lists are dynamic collections that can grow or shrink in size as needed. In .NET, the List<T> class provides a powerful and flexible way to store and manipulate collections of objects, where T represents the type of elements in the list.

Lists are part of the System.Collections.Generic namespace and offer numerous methods and properties to add, remove, search, and sort elements. Whether you're building a simple console application or a complex web service, understanding how to work with lists is an essential skill for any .NET developer.

Creating Lists

Let's start by learning how to create a list in C#:

csharp
// Import the necessary namespace
using System.Collections.Generic;

// Create an empty list of integers
List<int> numbers = new List<int>();

// Create a list with initial capacity
List<string> names = new List<string>(10);

// Create a list with initial values
List<double> prices = new List<double> { 19.99, 29.99, 39.99 };

The <T> in List<T> represents the type parameter - it specifies what type of elements the list will contain. You can create lists of any type, including built-in types (like int, string, bool) and custom classes or structs.

Basic List Operations

Adding Elements

You can add elements to a list using the Add method or AddRange for multiple items:

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

// Add individual items
fruits.Add("Apple");
fruits.Add("Banana");
fruits.Add("Cherry");

// Output: Count = 3
Console.WriteLine($"Count = {fruits.Count}");

// Add multiple items at once
fruits.AddRange(new string[] { "Orange", "Mango", "Pineapple" });

// Output: Count = 6
Console.WriteLine($"Count = {fruits.Count}");

Accessing Elements

You can access list elements by index, just like with arrays:

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

// Access the first element (index 0)
string firstFruit = fruits[0];
Console.WriteLine(firstFruit); // Output: Apple

// Access the last element
string lastFruit = fruits[fruits.Count - 1];
Console.WriteLine(lastFruit); // Output: Cherry

Removing Elements

Lists offer several ways to remove elements:

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

// Remove a specific element (first occurrence)
fruits.Remove("Banana");
// Now: Apple, Cherry, Banana, Mango

// Remove element at specific index
fruits.RemoveAt(1);
// Now: Apple, Banana, Mango

// Remove a range of elements (starting index, count)
fruits.RemoveRange(0, 1);
// Now: Banana, Mango

// Clear all elements
fruits.Clear();
// Now: empty list

Searching and Checking

Lists provide methods to search for elements and check for their existence:

csharp
List<int> numbers = new List<int> { 10, 20, 30, 40, 50, 30 };

// Check if an element exists
bool contains30 = numbers.Contains(30);
Console.WriteLine($"Contains 30: {contains30}"); // Output: Contains 30: True

// Find the index of the first occurrence
int firstIndex = numbers.IndexOf(30);
Console.WriteLine($"First index of 30: {firstIndex}"); // Output: First index of 30: 2

// Find the index of the last occurrence
int lastIndex = numbers.LastIndexOf(30);
Console.WriteLine($"Last index of 30: {lastIndex}"); // Output: Last index of 30: 5

// Check if any element satisfies a condition
bool hasEvenNumber = numbers.Exists(n => n % 2 == 0);
Console.WriteLine($"Has even number: {hasEvenNumber}"); // Output: Has even number: True

Iterating Through Lists

You can iterate through a list using several approaches:

csharp
List<string> colors = new List<string> { "Red", "Green", "Blue", "Yellow" };

// Using for loop
Console.WriteLine("Using for loop:");
for (int i = 0; i < colors.Count; i++)
{
Console.WriteLine(colors[i]);
}

// Using foreach loop (recommended)
Console.WriteLine("\nUsing foreach loop:");
foreach (string color in colors)
{
Console.WriteLine(color);
}

// Using ForEach method with a lambda expression
Console.WriteLine("\nUsing ForEach method:");
colors.ForEach(color => Console.WriteLine(color));

Sorting and Transforming Lists

Lists can be sorted and transformed using various methods:

csharp
List<int> numbers = new List<int> { 5, 2, 8, 1, 7, 3 };

// Sort the list in ascending order
numbers.Sort();
Console.WriteLine("Sorted: " + string.Join(", ", numbers));
// Output: Sorted: 1, 2, 3, 5, 7, 8

// Reverse the order
numbers.Reverse();
Console.WriteLine("Reversed: " + string.Join(", ", numbers));
// Output: Reversed: 8, 7, 5, 3, 2, 1

// Convert all elements (using ConvertAll)
List<string> numberStrings = numbers.ConvertAll(n => $"Number: {n}");
Console.WriteLine("Converted: " + string.Join(", ", numberStrings));
// Output: Converted: Number: 8, Number: 7, Number: 5, Number: 3, Number: 2, Number: 1

Working with Complex Objects

Lists can store complex objects, not just primitive types:

csharp
// Define a simple class
public class Person
{
public string Name { get; set; }
public int Age { get; set; }

public override string ToString()
{
return $"{Name} ({Age})";
}
}

// Create and use a list of Person objects
List<Person> people = new List<Person>
{
new Person { Name = "Alice", Age = 30 },
new Person { Name = "Bob", Age = 25 },
new Person { Name = "Charlie", Age = 35 }
};

// Find a person
Person bob = people.Find(p => p.Name == "Bob");
Console.WriteLine(bob); // Output: Bob (25)

// Sort by age
people.Sort((p1, p2) => p1.Age.CompareTo(p2.Age));
Console.WriteLine("Sorted by age: " + string.Join(", ", people));
// Output: Sorted by age: Bob (25), Alice (30), Charlie (35)

// Filter people older than 25
List<Person> olderPeople = people.FindAll(p => p.Age > 25);
Console.WriteLine("People older than 25: " + string.Join(", ", olderPeople));
// Output: People older than 25: Alice (30), Charlie (35)

Real-World Examples

Example 1: Task Manager

Here's a simple task manager application that uses a list to store tasks:

csharp
public class Task
{
public string Description { get; set; }
public bool IsCompleted { get; set; }
}

public class TaskManager
{
private List<Task> tasks = new List<Task>();

public void AddTask(string description)
{
tasks.Add(new Task { Description = description, IsCompleted = false });
Console.WriteLine($"Added task: {description}");
}

public void CompleteTask(int index)
{
if (index >= 0 && index < tasks.Count)
{
tasks[index].IsCompleted = true;
Console.WriteLine($"Completed task: {tasks[index].Description}");
}
else
{
Console.WriteLine("Invalid task index.");
}
}

public void DisplayTasks()
{
if (tasks.Count == 0)
{
Console.WriteLine("No tasks.");
return;
}

Console.WriteLine("Tasks:");
for (int i = 0; i < tasks.Count; i++)
{
string status = tasks[i].IsCompleted ? "[✓]" : "[ ]";
Console.WriteLine($"{i}: {status} {tasks[i].Description}");
}
}
}

// Usage:
TaskManager manager = new TaskManager();
manager.AddTask("Learn about .NET Lists");
manager.AddTask("Complete programming assignment");
manager.AddTask("Write documentation");
manager.DisplayTasks();
manager.CompleteTask(0);
manager.DisplayTasks();

Example 2: Shopping Cart

Here's an implementation of a shopping cart using lists:

csharp
public class Product
{
public string Name { get; set; }
public decimal Price { get; set; }

public override string ToString()
{
return $"{Name}: ${Price}";
}
}

public class ShoppingCart
{
private List<Product> items = new List<Product>();

public void AddProduct(Product product)
{
items.Add(product);
Console.WriteLine($"Added {product.Name} to cart.");
}

public void RemoveProduct(int index)
{
if (index >= 0 && index < items.Count)
{
Console.WriteLine($"Removed {items[index].Name} from cart.");
items.RemoveAt(index);
}
else
{
Console.WriteLine("Invalid product index.");
}
}

public decimal CalculateTotal()
{
decimal total = 0;
foreach (var item in items)
{
total += item.Price;
}
return total;
}

public void DisplayCart()
{
if (items.Count == 0)
{
Console.WriteLine("Your cart is empty.");
return;
}

Console.WriteLine("Shopping Cart:");
for (int i = 0; i < items.Count; i++)
{
Console.WriteLine($"{i}: {items[i]}");
}
Console.WriteLine($"Total: ${CalculateTotal()}");
}
}

// Usage:
ShoppingCart cart = new ShoppingCart();
cart.AddProduct(new Product { Name = "Laptop", Price = 999.99m });
cart.AddProduct(new Product { Name = "Mouse", Price = 24.99m });
cart.AddProduct(new Product { Name = "Keyboard", Price = 59.99m });
cart.DisplayCart();
cart.RemoveProduct(1);
cart.DisplayCart();

Performance Considerations

When working with lists, keep these performance considerations in mind:

  1. Initial Capacity: When you know the approximate number of elements beforehand, specify an initial capacity to reduce the number of resizing operations:

    csharp
    // More efficient for large lists
    List<int> numbers = new List<int>(10000);
  2. Add vs Insert: Adding to the end of a list (Add) is much faster than inserting at the beginning or middle (Insert), which requires shifting elements.

  3. Contains vs Binary Search: For sorted lists, use BinarySearch instead of Contains for better performance with large collections:

    csharp
    List<int> sortedNumbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    int index = sortedNumbers.BinarySearch(7); // More efficient for sorted lists
  4. Clear vs New: When you need to empty a list, use Clear() instead of creating a new instance if you plan to reuse the list. This preserves the allocated capacity.

Summary

.NET Lists are versatile data structures that provide dynamic storage for collections of elements. They offer numerous methods for adding, removing, searching, and manipulating data, making them an essential tool in a developer's toolbox.

Key points to remember about lists:

  • Lists are dynamic and can grow or shrink as needed
  • They provide type safety through generic implementation (List<T>)
  • Lists offer methods for common operations like adding, removing, finding, and sorting elements
  • They can store both simple types and complex objects
  • Lists are indexed from 0, like arrays

Mastering lists is fundamental for effective C# and .NET development, as they are used in countless programming scenarios, from simple data management to complex application architectures.

Exercises

  1. Create a program that reads a list of names from the console and then prints them in alphabetical order.
  2. Implement a simple to-do list application that allows adding, removing, and marking tasks as complete.
  3. Create a program that manages a playlist of songs, allowing the user to add, remove, and shuffle songs.
  4. Implement a method that takes two lists and returns a new list containing only the elements that appear in both lists.
  5. Create a program that reads a list of numbers and calculates various statistics like minimum, maximum, average, and median.

Additional Resources



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)