CodeGym /Courses /C# SELF /List: List<T>...

List: List<T>

C# SELF
Level 27, Lesson 2
Available

1. Introduction

Imagine you're keeping a shopping list. Today you need to buy 3 items, tomorrow — 10, and the day after — just one. If you used an array, you'd have to create a new array every time for the exact number of items. Or you'd make a huge array "just in case," and end up "carrying" a bunch of empty slots. Not super efficient, right?

Now imagine you have a magic backpack that expands itself when you add stuff and shrinks when you take things out. You don't need to know ahead of time how much you'll put in. You just toss things in, and the backpack adapts. That's basically what List<T> is in the C# programming world!

List<T> is a generic collection that lets you store a sequence of elements of a certain type. The key word here is "dynamic". Unlike arrays, List<T> can change its size while your program is running. It manages its own internal capacity, bumping it up when needed.

What does the letter T mean in List<T>? That's called a type parameter. When you create a List, you tell it what data type it'll store instead of T. For example, List<int> will only store integers, List<string> — only strings, and List<double> — only doubles. This makes sure you can't accidentally add an apple to a list of oranges, which is super important for your code's stability and predictability.

Why do we need this?

In real projects, it's super common that you don't know ahead of time how many elements you'll have. For example:

  • A list of users who logged into a website.
  • A list of items in a shopping cart.
  • A list of search results for a query.
  • A list of tasks in a scheduler, which we're about to build.

In all these cases, the number of elements can change, and List<T> becomes your go-to helper.

Main methods of List<T>

Method Description Example
Add(T item)
Add an element to the end of the list
numbers.Add(5);
Insert(int idx, T)
Insert at a specific position
numbers.Insert(0, 42);
Remove(T item)
Remove the first occurrence of an element
numbers.Remove(100);
RemoveAt(int idx)
Remove an element by index
numbers.RemoveAt(2);
Clear()
Clear the list
numbers.Clear();
Contains(T item)
Check if the list has an element
numbers.Contains(10);
IndexOf(T item)
Index of the first occurrence
int pos = numbers.IndexOf(42);
Count
Number of elements in the list
int n = numbers.Count;
Capacity
Internal buffer capacity
numbers.Capacity = 100;

2. Creating a list (List<T>)

Let's get practical! Imagine we decided to make a simple task manager. We need a list where we'll add our tasks.

To create a new List<T>, we use the new operator, just like with other objects.

How to declare and create a List

The syntax for creating a list is a lot like an array, but with angle brackets instead of square ones:

using System.Collections.Generic;

List<int> numbers = new List<int>();

Notes for those who love details:
- List<int> is a list of integers (int). Instead of int you can use any other type: string, double, your own class, whatever.
- After creation, the list is empty — its length is 0.

Example: first step in building our app

Let's say we have an app where the user entered their name and age (from the very first lectures). Now let's add the ability to save several names in a list, so we can work with them later.

using System;
using System.Collections.Generic;

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

        Console.WriteLine("Enter three names:");
        for (int i = 0; i < 3; i++)
        {
            string name = Console.ReadLine();
            names.Add(name);
        }

        Console.WriteLine("You entered:");
        foreach (string n in names)
        {
            Console.WriteLine(n);
        }
    }
}

Check out Add(). That's the method that adds new elements to the list. Basically — that's what makes it dynamic!

You can create a list with elements right away!

List<string> planets = new List<string> { "Mercury", "Venus", "Earth" };

Super handy when you know your "starting lineup." This syntax is often used in tests and when initializing fixed data.

3. Basic operations with List<T>

Before we get to the tricks and magic, let's go through the "ABC" of lists.

Adding elements: Add()

Using the Add() method is like putting a new thing on a shelf:

List<int> numbers = new List<int>();
numbers.Add(42);
numbers.Add(100);

Now inside: [42, 100]

Getting the number of elements: Count

Unlike arrays, lists use the property Count instead of Length:

int count = numbers.Count; // Returns 2

Remember: lists use the Count property, but arrays and strings use Length. Different properties, similar purpose.

Accessing elements by index

Two ways, both basically the same:

int first = numbers[0]; // 42
numbers[1] = 200; // Changed 100 to 200

Important: Indexing, just like with arrays, starts at zero. Don't try to access numbers[3] if you only have three elements!

Looping through list elements

You can use a for loop or a foreach loop:

// Using for — if you need the index
for (int i = 0; i < numbers.Count; i++)
{
    Console.WriteLine(numbers[i]);
}

// Using foreach — if you don't need the index
foreach (int number in numbers)
{
    Console.WriteLine(number);
}

foreach is usually simpler and clearer, especially for big collections.
But with it, you can't change elements by index or break out of the loop early with break, unless you use extra tricks.

Inserting an element by index: Insert()

The Insert() method is for when you want to add an element not at the end, but anywhere you want. For example, in the second spot:

numbers.Insert(1, 55); // Inserts 55 at index 1

Now numbers: [42, 55, 200]

Removing elements

Removing from a list is almost as easy as adding:

numbers.Remove(55); // Removes the FIRST occurrence of 55
numbers.RemoveAt(0); // Removes the element at index 0
numbers.Clear(); // Completely clears the list

Removal gotchas:
- If you try to remove a value that doesn't exist with Remove, nothing bad happens: the list stays the same, no errors.
- After Clear() the list is empty again.

4. Handy details

How List<T> grows

When you add elements to a List<T>, it doesn't bump up its size a little every time. Instead, List<T> allocates a chunk of memory with some extra space (the internal capacity — Capacity).

As soon as you have more elements than the current capacity, the list allocates a new, bigger chunk of memory (usually twice as big) and copies all the old values there:


Adding elements → fits → fits → fits →
New element doesn't fit → bigger array is created → data is copied → keep going

This lets you add elements faster, since memory is only reallocated every once in a while, not on every Add.

var list = new List<int>();    // Capacity = 0
list.Add(1);                   // Capacity = 4
list.Add(2);                   // Capacity = 4
list.Add(3);                   // Capacity = 4
list.Add(4);                   // Capacity = 4
list.Add(5);                   // Capacity = 8 (expansion!)

Capacity vs. Count: what's the difference?

  • Count — number of elements you've added to the list.
  • Capacity — size of the internal array holding the elements.
List<int> nums = new List<int>();
Console.WriteLine(nums.Count); // 0
Console.WriteLine(nums.Capacity); // Usually 0 or a small number

nums.Add(123);
Console.WriteLine(nums.Count); // 1
Console.WriteLine(nums.Capacity); // Now might be bigger than Count

nums.Capacity = 1000; // You can bump up Capacity if you know you'll have a lot of elements

Most devs just use Count, but if you're writing performance-heavy apps (like games or data analysis), fine-tuning Capacity can be useful.

5. Example

Let's keep building our little app — now, for example, the user can add their favorite numbers, and then work with the list: insert, remove, print, and clear.

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<int> favoriteNumbers = new List<int>();

        Console.WriteLine("Enter your favorite numbers (one per line, 0 — finish):");
        while (true)
        {
            int num = int.Parse(Console.ReadLine());
            if (num == 0) break;
            favoriteNumbers.Add(num);
        }

        Console.WriteLine("Your favorite numbers:");
        foreach (int n in favoriteNumbers)
        {
            Console.Write(n + " ");
        }

        Console.WriteLine("\nWant to remove the first number? (y/n)");
        if (Console.ReadLine().ToLower() == "y")
        {
            favoriteNumbers.RemoveAt(0);
        }

        Console.WriteLine("Now your list:");
        foreach (int n in favoriteNumbers)
        {
            Console.Write(n + " ");
        }
    }
}

Note: Here we're using int.Parse. In real projects, it's always better to check input for correctness with int.TryParse, so your program doesn't "crash" on any user mistake.

6. Common mistakes and "gotchas" for beginners

A super common scenario: you write a loop from 0 to List.Count, but during the loop (like in a foreach) you change the list itself (add or remove elements). Don't do that! Pro devs call this "modifying a collection while iterating." Most of the time, you'll instantly get an InvalidOperationException.

Example of bad code:

foreach (int n in numbers)
{
    if (n < 0)
        numbers.Remove(n); // BOOM! Runtime error.
}

The right way: either collect the indexes/elements to remove in a separate list first, or use a for loop going backwards.

2
Task
C# SELF, level 27, lesson 2
Locked
Working with strings in List
Working with strings in List
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION