Skip to main content

📝 Lesson 4.1: Collections — Arrays and Lists

So far each variable held a single value. But real programs juggle many values — a list of scores, names, or prices. Collections let you store and work with groups of data.

🎯 Learning Objectives

By the end of this lesson, you will be able to:

  • Create and use arrays to store fixed groups of values
  • Access items by index and understand zero-based counting
  • Loop through collections with for and foreach
  • Use a List<T> for groups that grow and shrink
  • Add, remove, and count items in a list

Estimated Time: 45 minutes

Project: Build a simple to-do list that grows as the user adds tasks.

In This Lesson

Why Collections?

Imagine storing five test scores. With what you know so far, you might write:

int score1 = 85;
int score2 = 92;
int score3 = 78;
int score4 = 90;
int score5 = 88;

That's already awkward — and hopeless for 500 scores. A collection holds many values under a single name, so you can store them together and process them with a loop.

📖 Definition

Collection: A single variable that holds multiple values. C#'s two most common beginner collections are the array (fixed size) and the List (flexible size).

Arrays

An array stores a fixed number of values of the same type. You declare the type followed by []. Here are two ways to create one:

// 1) Create with known values
int[] scores = { 85, 92, 78, 90, 88 };

// 2) Create empty with a fixed size, then fill it
int[] temps = new int[3];   // three slots, all start at 0
temps[0] = 20;
temps[1] = 25;
temps[2] = 22;

Picture an array as a row of numbered boxes, all holding the same type of thing:

graph LR A["[0]
85"] --- B["[1]
92"] --- C["[2]
78"] --- D["[3]
90"] --- E["[4]
88"] style A fill:#eff6ff,stroke:#3b82f6,stroke-width:2px style E fill:#eff6ff,stroke:#3b82f6,stroke-width:2px

⚠️ Arrays have a fixed size

Once created, an array's length can't change. An int[5] always has exactly 5 slots. If you need to add or remove items as the program runs, you want a List (later in this lesson).

Indexing and Zero-Based Counting

You access an item by its index — its position number — using square brackets. Here's the twist that surprises every beginner:

⚠️ Counting starts at 0

The first item is at index 0, the second at 1, and so on. So in an array of 5 items, the valid indexes are 0, 1, 2, 3, 4 — the last index is always length minus 1.

int[] scores = { 85, 92, 78, 90, 88 };

Console.WriteLine(scores[0]);   // 85  (first item)
Console.WriteLine(scores[4]);   // 88  (last item)

scores[1] = 100;                // change the second item
Console.WriteLine(scores[1]);   // 100

Console.WriteLine(scores.Length);   // 5  (how many items)

⚠️ Out-of-range crashes

Asking for an index that doesn't exist — like scores[5] in a 5-item array (valid indexes are 0–4) — throws an IndexOutOfRangeException and stops the program. Always remember: last index = Length - 1.

Looping Through Arrays

This is where collections and loops (Lesson 3.2) come together beautifully. To visit every item, use a loop instead of writing a line per element.

With foreach (simplest)

int[] scores = { 85, 92, 78, 90, 88 };

foreach (int score in scores)
{
    Console.WriteLine(score);
}

With for (when you need the index)

int[] scores = { 85, 92, 78, 90, 88 };

for (int i = 0; i < scores.Length; i++)
{
    Console.WriteLine($"Score #{i + 1} is {scores[i]}");
}

Output:

Score #1 is 85
Score #2 is 92
Score #3 is 78
Score #4 is 90
Score #5 is 88

💡 The classic pattern: i < Length

Notice the condition is i < scores.Length (less-than), not <=. Because indexes stop at Length - 1, using < visits exactly the valid range. Using <= here would run off the end and crash — a very common beginner bug.

Here's a practical combination — summing an array and computing an average:

int[] scores = { 85, 92, 78, 90, 88 };
int total = 0;

foreach (int score in scores)
{
    total += score;
}

double average = (double)total / scores.Length;
Console.WriteLine($"Total: {total}, Average: {average:F1}");
// Total: 433, Average: 86.6

(The (double) converts total to a double so we get a decimal average instead of falling into the integer-division trap from Lesson 2.2.)

Lists: Collections That Grow

Arrays are great when you know the size ahead of time. But often you don't — think of a shopping list you add to as you go. For that, use a List<T>, which can grow and shrink as your program runs.

The <T> part is the type of item the list holds — List<int> is a list of ints, List<string> a list of strings. (You may need using System.Collections.Generic; at the top in older project styles; modern templates include it automatically.)

// A list of strings, starting empty
List<string> tasks = new List<string>();

tasks.Add("Buy milk");
tasks.Add("Walk the dog");
tasks.Add("Write C# code");

Console.WriteLine(tasks.Count);   // 3

// You can also start with items:
List<int> scores = new List<int> { 85, 92, 78 };

Indexing and looping work just like arrays:

Console.WriteLine(tasks[0]);   // Buy milk

foreach (string task in tasks)
{
    Console.WriteLine($"- {task}");
}

💡 Count vs Length

Arrays use .Length; lists use .Count. Both tell you how many items there are — just remember which name goes with which.

Common List Operations

Lists come with handy built-in methods. Here are the ones you'll use most:

OperationCodeWhat it does
Add an itemlist.Add("x")Appends to the end
Remove an itemlist.Remove("x")Removes the first match
Remove by indexlist.RemoveAt(0)Removes the item at that position
Count itemslist.CountHow many items are in the list
Check membershiplist.Contains("x")Returns true/false
Empty itlist.Clear()Removes all items
List<string> tasks = new List<string> { "Buy milk", "Walk the dog" };

tasks.Add("Write C# code");         // now 3 items
tasks.Remove("Buy milk");           // now 2 items
Console.WriteLine(tasks.Count);     // 2
Console.WriteLine(tasks.Contains("Walk the dog"));   // True

foreach (string task in tasks)
{
    Console.WriteLine(task);
}
// Walk the dog
// Write C# code

✅ Array or List?

Use an array when the number of items is fixed and known. Use a List when items are added or removed while the program runs — which, in practice, is most of the time.

Exercise & Quiz

🏋️ Exercise: An Interactive To-Do List

Objective: Combine a List, a loop, and user input into a small useful program.

Instructions:

  1. Create a new project called TodoList.
  2. Make an empty List<string> for tasks.
  3. Repeatedly ask the user to enter a task. Keep adding tasks to the list until they type done.
  4. When finished, print how many tasks there are, then print each task on its own numbered line.

Starter Code:

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

Console.Write("Enter a task (or 'done' to finish): ");
string input = Console.ReadLine();

while (input != "done")
{
    // TODO: add input to the list, then prompt + read again
}

// TODO: print the count, then each task numbered
💡 Hint

Inside the loop: tasks.Add(input); then prompt and read the next line. To number tasks when printing, a for loop gives you the index: print $"{i + 1}. {tasks[i]}".

✅ Solution
List<string> tasks = new List<string>();

Console.Write("Enter a task (or 'done' to finish): ");
string input = Console.ReadLine();

while (input != "done")
{
    tasks.Add(input);
    Console.Write("Enter a task (or 'done' to finish): ");
    input = Console.ReadLine();
}

Console.WriteLine($"\nYou have {tasks.Count} task(s):");
for (int i = 0; i < tasks.Count; i++)
{
    Console.WriteLine($"{i + 1}. {tasks[i]}");
}

Sample run:

Enter a task (or 'done' to finish): Buy milk
Enter a task (or 'done' to finish): Walk the dog
Enter a task (or 'done' to finish): done

You have 2 task(s):
1. Buy milk
2. Walk the dog

(\n in the string prints a blank line — a handy way to add spacing.)

🎯 Quick Quiz

Question 1: In the array int[] a = { 10, 20, 30 };, what is a[0]?

Question 2: What's the main difference between an array and a List<T>?

Question 3: To visit every element of an array with a for loop, the condition should be:

Summary

🎉 Key Takeaways

  • A collection stores many values under one name. Arrays are fixed-size; List<T> can grow and shrink.
  • Items are accessed by index, and indexing is zero-based — the last index is Length - 1.
  • Loop with foreach to visit every item, or for when you need the index; use i < length, not <=.
  • Lists offer Add, Remove, RemoveAt, Contains, Clear, and Count.
  • Arrays use .Length; lists use .Count. Choose a List when items change at runtime.

📚 Additional Resources

🚀 What's Next?

You can now group data together. Next, we learn to bundle data and behavior into custom types of our own. In Lesson 4.2: Introduction to Object-Oriented Programming, you'll create your own classes — the foundation of modern C#.

🎉 Data, grouped!

Collections plus loops and methods are a serious toolkit. Next, we design our own data types.