Start learning free

LESSON 114 OF 674 · ARRAYS I

Slicing a List in C# with GetRange

Lesson Read the full explanation

TL ; DR:

list.GetRange(i, count) is a new List with count items, starting at index i. The original List doesn't change.


List<string> letters = new List<string>(new[] {"a", "b", "c", "d", "e"});

List<string> middle = letters.GetRange(1, 3);
// middle is [b, c, d]

// letters is still [a, b, c, d, e]


Full lesson:

Sometimes you need only part of a List, like the first few items. The GetRange method copies that part into a new List.

Careful: it takes a start index and a count, not an end index. So GetRange(1, 3) means three items, starting at index 1.

For the items from index i up to j (not included), the count is j - i. So GetRange(1, 3) gives the items at 1, 2 and 3.

To go to the very end, count what's left after the start:

List<string> tail = letters.GetRange(3, letters.Count - 3);
// tail is [d, e]

The new List is a copy. The original stays as it was.


Your task

runners holds a race's runners, in the order they finished.

Put the first three in a new List named podium. Put everyone else, from index 3 to the end, in one named rest.

The code below prints both, then the length of runners.

Expected output:

Ana Ben Cleo
Dan Eve
5
STEP 1 OF 2
    Ctrl + Enter to check

    C# · ARRAYS I

    Array Slicing in C#, explained

    Copying part of a list

    Sometimes you need only part of a List<T>: the first few items, or everything after a certain position. GetRange(start, count) copies that part into a new list. Its two arguments are a start index and a count, how many items to copy. They are not a start and an end index.

    List<string> letters = new List<string>(new[] {"a", "b", "c", "d", "e"});
    List<string> middle = letters.GetRange(1, 3);
    Console.WriteLine(string.Join(" ", middle));
    Console.WriteLine(string.Join(" ", letters));
    
    b c d
    a b c d e
    

    GetRange(1, 3) means three items, starting at index 1: the items at indexes 1, 2 and 3. The original list is untouched. In a file of your own, add using System; and using System.Collections.Generic;.

    From an end index to a count

    If you think in terms of "from index i up to, but not including, index j", the count is j - i. For i = 1 and j = 4, the count is 3, and GetRange(i, j - i) gives b c d again.

    To slice to the very end, count what is left after the start:

    List<string> tail = letters.GetRange(3, letters.Count - 3);
    

    That gives d e. The start index 3 plus the count 2 reaches exactly the end of the list.

    A LINQ alternative

    With using System.Linq;, Skip and Take do similar jobs, and they do not throw when the list is too short. letters.Skip(3).ToList() gives d e, and letters.Take(10).ToList() on five items simply returns all five. The lesson uses GetRange because it is a method of List<T> itself, so it needs no extra using, and it states the start and the count explicitly.

    The exercise, step by step

    runners holds five runners in the order they finished: Ana, Ben, Cleo, Dan, Eve.

    1. The podium. The first three runners start at index 0, and there are 3 of them: runners.GetRange(0, 3). Store the result in podium.
    2. Everyone else. They start at index 3. The count is what is left after the podium: runners.Count - 3, which is 2. Store it in rest.
    List<string> runners = new List<string>(new[] {"Ana", "Ben", "Cleo", "Dan", "Eve"});
    List<string> podium = runners.GetRange(0, 3);
    List<string> rest = runners.GetRange(3, runners.Count - 3);
    Console.WriteLine(podium[0] + " " + podium[1] + " " + podium[2]);
    Console.WriteLine(rest[0] + " " + rest[1]);
    Console.WriteLine(runners.Count);
    
    Ana Ben Cleo
    Dan Eve
    5
    

    The last line shows that runners still has five items: slicing copies, it does not remove.

    Traps to avoid

    • Treating the second argument as an end index. runners.GetRange(1, 3) returns three items, not the items before index 3. Remember it as "how many".
    • Asking for too many. The range must fit inside the list. runners.GetRange(3, 4) on five items throws an ArgumentException, and a negative start or count throws an ArgumentOutOfRangeException. Unlike some other languages, C# does not shorten the range for you.
    • An empty slice is allowed. GetRange(5, 0) on five items starts at the end and returns an empty list.
    • The copy is shallow. The new list is separate, so changing podium[0] does not change runners[0]. But if the items are themselves objects, such as arrays, both lists point to the same objects.
    • Forgetting the copy exists. Assign the result to a variable, or the new list is lost.

    Key takeaways

    • list.GetRange(i, count) returns a new list with count items from index i.
    • For items from i up to j (not included), the count is j - i.
    • To the end of the list, use list.Count - i.
    • The original list does not change, and a range that does not fit in the list throws an exception.
    Keep going with C#500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free