📝 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
forandforeach - 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:
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:
| Operation | Code | What it does |
|---|---|---|
| Add an item | list.Add("x") | Appends to the end |
| Remove an item | list.Remove("x") | Removes the first match |
| Remove by index | list.RemoveAt(0) | Removes the item at that position |
| Count items | list.Count | How many items are in the list |
| Check membership | list.Contains("x") | Returns true/false |
| Empty it | list.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:
- Create a new project called
TodoList. - Make an empty
List<string>for tasks. - Repeatedly ask the user to enter a task. Keep adding tasks to the list until they type
done. - 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
foreachto visit every item, orforwhen you need the index; usei < length, not<=. - Lists offer
Add,Remove,RemoveAt,Contains,Clear, andCount. - 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.