Menu

C# List: Add, Remove, Contains, Find and Sort

List<T> is the growable array of C#. Learn how to create a list, add and insert items, remove by value, index or condition, search with Contains and Find, sort by a property, and avoid the error from changing a list inside foreach.

This page includes runnable editors - edit, run, and see output instantly.

List<T> is an ordered collection that grows and shrinks as you add and remove items. It lives in System.Collections.Generic, indexes like an array (list[0]), and is the default choice for "a bunch of things" in C#.

Creating a list and adding items

The type parameter in angle brackets says what the list holds: List<string>, List<int>, List<Order>.

Output:

2
Zoe, Ana, Ben, Chloe, Dev
Ana
Ana B.
3

Count is a property, not a method (arrays use Length, LINQ has a Count() method; on a list use the property). Insert shifts every later item one place along, so inserting at the front of a large list costs time proportional to its size. Add at the end is the cheap operation.

Removing items

There are four ways to remove, depending on what you know about the item:

Output:

True: 85, 62, 40, 91, 55
False
62, 40, 91, 55
2 removed: 62, 91
Caught ArgumentOutOfRangeException
0

Remove takes a value and deletes only the first match. To delete all copies of a value, use RemoveAll(s => s == 40). A bad index on a list throws ArgumentOutOfRangeException (an array throws IndexOutOfRangeException instead), both for list[i] and for RemoveAt(i). RemoveRange(index, count) removes a block.

Count vs Capacity

A list keeps its items in an internal array. Capacity is that array's size; Count is how many slots are used. When Count reaches Capacity, the next Add allocates an array twice as large and copies everything over.

Output:

Count 0, Capacity 0
Count 1, Capacity 4
Count 2, Capacity 4
Count 3, Capacity 4
Count 4, Capacity 4
Count 5, Capacity 8
Count 6, Capacity 8
Count 7, Capacity 8
Count 8, Capacity 8
Count 9, Capacity 16
Count 0, Capacity 1000

Doubling means most Add calls are just a write into a free slot. If you know roughly how many items are coming, pass the number to the constructor to skip the intermediate copies. Note that new List<int>(1000) still has Count 0: list[0] on it throws. Capacity is room, not items.

Searching: Contains, IndexOf, Find, Exists

Output:

True
2
-1
32.00
2 cheap items
False
2
True
False

Find returns the first match or the type's default value (null for a class) when nothing matches, so check before using the result. The last line prints False because Contains uses Equals, and a class without an Equals override compares references: a new Product with the same fields is a different object. Search by a property with Exists or Find instead, or override Equals and GetHashCode on the class.

Every one of these methods walks the list from the start, so each call is O(n). For repeated lookups by a key, a Dictionary answers in constant time.

Sorting a list

Sort() sorts in place using the items' natural order. Pass a comparison lambda to sort by anything else.

Output:

1, 2, 5, 9
9, 5, 2, 1
Ben 95, Ana 120, Chloe 150
Chloe 150, Ben 95, Ana 120
Ben 95, Ana 120, Chloe 150

A comparison returns a negative number when a should come first, positive when b should, and zero when they tie; CompareTo produces exactly that. Two differences between Sort and LINQ's OrderBy matter in practice:

  • Sort changes the list; OrderBy returns a new sequence and leaves the list alone.
  • Sort is not stable: items that compare equal can swap places. OrderBy is stable, and ThenBy adds a second key: players.OrderBy(p => p.Score).ThenBy(p => p.Name).

Calling Sort() on a list of your own class without a comparison throws InvalidOperationException, because the list does not know how to order the items. Either pass a comparison or implement IComparable<T> on the class.

Reverse() reverses in place. Because System.Linq also defines a Reverse extension, list.Reverse() on a List<T> picks the in-place version, which returns nothing.

Looping, and removing while iterating

foreach reads every item in order. A for loop gives you the index as well. What you cannot do is add or remove items in the middle of a foreach over the same list:

Output:

Caught InvalidOperationException
120, 80, 60
120, 80, 60

The exception is InvalidOperationException with the message "Collection was modified; enumeration operation may not execute." A forward for loop does not throw, but it silently skips the item right after each one you remove, because everything shifts down one index. Looping backwards avoids that. A third fix is iterating over a copy: foreach (var t in orders.ToList()).

Changing a property of an item inside foreach (for example order.Status = "sent") is fine. Adding or removing items breaks the enumerator, and so does replacing one through the indexer (orders[i] = 0).

Converting between lists and arrays

Output:

4
3
4, 4, 4, 4
Oslo / Lima / Pune / Kyiv

Both directions copy the elements into new storage, so changing the list later does not affect the array. ConvertAll is the list's own version of LINQ's Select(...).ToList(). Printing a list with Console.WriteLine(list) shows the type name (System.Collections.Generic.List`1[System.String]); use string.Join.

Quick reference

TaskCode
Createvar l = new List<int>(); or new List<int> { 1, 2 }
Add at endl.Add(x), l.AddRange(items)
Insert at positionl.Insert(i, x)
Remove first matchl.Remove(x) (returns bool)
Remove by indexl.RemoveAt(i)
Remove by conditionl.RemoveAll(x => ...) (returns count)
Number of itemsl.Count
Containsl.Contains(x), l.Exists(x => ...)
Findl.Find(...), l.FindAll(...), l.FindIndex(...)
Sort in placel.Sort(), l.Sort((a, b) => ...)
Sorted copyl.OrderBy(x => ...).ToList()
To arrayl.ToArray()

Common mistakes

  • Removing inside foreach. Throws InvalidOperationException; use RemoveAll or a backwards for loop.
  • Expecting Remove(x) to remove every copy. It removes the first; use RemoveAll.
  • Using Contains on objects without Equals. It compares references; search by property with Exists.
  • Indexing into a list created with a capacity. new List<int>(10) is empty; add items first.
  • Assuming Sort keeps ties in order. It does not; use OrderBy when order among equals matters.
  • Assigning a list to share it, then being surprised by changes. var copy = list; is the same list; new List<T>(list) is a copy.

Frequently Asked Questions

How do I add items to a List in C#?

list.Add(item) appends one item at the end, list.AddRange(otherCollection) appends many, and list.Insert(index, item) puts an item at a position and shifts the rest along. You can also fill a list when you create it: var names = new List<string> { "Ana", "Ben" };.

How do I remove an item from a List in C#?

Remove(value) removes the first matching item and returns true if it found one. RemoveAt(index) removes by position. RemoveAll(x => condition) removes every item that matches and returns how many it removed. Clear() empties the list.

How do I check if a List contains a value in C#?

list.Contains(value) returns true or false. It compares with Equals, so for your own classes it compares references unless the class overrides Equals. To check by a property, use list.Exists(p => p.Name == "Ana") or LINQ's list.Any(...).

How do I sort a List by a property in C#?

Pass a comparison to Sort: people.Sort((a, b) => a.Age.CompareTo(b.Age)) sorts in place. Swap a and b for descending order. Or use LINQ, which returns a new sorted sequence and keeps equal items in their original order: people.OrderBy(p => p.Age).ToList().

Why do I get "Collection was modified; enumeration operation may not execute"?

You added, removed or replaced (list[i] = x) items while a foreach was iterating over the same list, and the enumerator throws InvalidOperationException on its next step. Use list.RemoveAll(condition), loop backwards with a for loop, or iterate over a copy such as list.ToList().

What is the difference between Count and Capacity?

Count is the number of items in the list. Capacity is the size of the internal array, which is at least Count. When the array fills up, the list allocates a new one twice as large and copies the items, so Add is fast on average.

Coddy programming languages illustration

Learn to code with Coddy

GET STARTED