Skip to content
Lists and Dictionaries
step 1/6

Reading — step 1 of 6

Learn

~3 min readCollections and LINQ

Lists and Dictionaries

Arrays are fixed-size: an int[5] holds five ints, forever. Real programs rarely know their sizes up front — so the collection you will reach for every day is List<T>, a dynamic array that grows as you add. Its partner Dictionary<K, V> is the hash map: instant lookup by key. Both live in System.Collections.Generic.

List<T>

using System.Collections.Generic;

var nums = new List<int> { 3, 1, 4 };   // collection initializer
nums.Add(1);                            // grows automatically
Console.WriteLine(nums.Count);          // 4  (Count, not Length)
Console.WriteLine(nums[0]);             // 3  (zero-indexed)
nums.RemoveAt(0);                       // remove by index
bool has = nums.Contains(4);            // search by value

The <int> is a generic type parameter: this list holds ints and nothing else, checked at compile time. No casts, no runtime surprises.

Dictionary<K, V>

var ages = new Dictionary<string, int> {
    ["Alice"] = 30,
    ["Bob"] = 25,
};
ages["Carol"] = 40;                     // indexer adds or overwrites

// Idiom: TryGetValue — the safe lookup
if (ages.TryGetValue("Dan", out int age)) {
    Console.WriteLine(age);
}

// Trap: indexing a missing key throws KeyNotFoundException
Console.WriteLine(ages["Dan"]);         // crash at runtime

TryGetValue returns false for a missing key instead of throwing — that one habit eliminates a whole family of crashes.

Parsing a line of numbers

Exercises — and real input handling — constantly need "one line of space-separated numbers into a collection". Two equivalent idioms:

// Loop style
var nums = new List<int>();
foreach (string part in Console.ReadLine().Split(' ')) {
    nums.Add(int.Parse(part));
}

// LINQ one-liner (what the starter uses — the next lesson explains it)
int[] nums = Console.ReadLine().Split(' ').Select(int.Parse).ToArray();

Split(' ') chops the line into pieces; each piece still needs parsing from string to int.

The trap: the max that starts at zero

Finding the largest element is a one-loop job — with a famous landmine in it:

// Trap: seeding max with 0
int max = 0;
foreach (int n in nums) {
    if (n > max) max = n;
}
// nums = [-10, -5, -1]  ->  max stays 0. Wrong: 0 is not even in the data!
// Idiom: seed with the FIRST element — a value actually in the data
int max = nums[0];
foreach (int n in nums) {
    if (n > max) max = n;
}

Seeding with 0 — or any made-up constant — silently fails on all-negative data, and "silently" is the dangerous part: it looks right on every happy-path test. Seed with nums[0] (or int.MinValue). Or skip the loop entirely: LINQ's nums.Max() does exactly this, correctly.

Your exercise

Read one line of space-separated integers — the starter parses it into nums for you — and print the largest one.

The grader's second test is -10 -5 -1, expecting -1: precisely the all-negative case that kills the max = 0 trap above. Seed from the data (nums[0]) or call nums.Max(), and print only the number. The hidden test is a single value, 42 — seeding from nums[0] handles that automatically too.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…