Creating a List of Lists in C
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
In C#, a list of lists is written as List<List<T>>. It is a flexible way to represent grouped or two-dimensional data when rows may have different lengths, but that flexibility comes with tradeoffs in indexing, memory layout, and accidental reference sharing.
Create a List<List<T>> Directly
The basic structure is straightforward.
This is useful when each inner list is a row or group whose size can vary independently.
Use Collection Initializers for Readability
If the data is known up front, collection initializers make the structure easier to read.
This is often the cleanest way to express small nested sample data in tests or examples.
Prebuild Rows in a Loop When Sizes Are Dynamic
When the outer list size is known but the row contents will be filled later, create each inner list separately.
The important detail is that each row must be a distinct list instance.
Avoid Accidental Reference Sharing
A common bug is reusing the same inner list object multiple times.
Both positions point to the same row object, so modifying one appears to modify both. If you want separate rows, create separate lists.
Iterate and Transform Safely
Nested iteration is simple with foreach.
You can also flatten the structure when needed.
That is useful for aggregate operations or searches across all nested values.
Know When a Different Structure Is Better
A List<List<T>> is good for ragged data, adjacency lists, grouped records, and user-editable rows. It is not always the best representation for a fixed rectangular matrix.
If every row has the same length and performance matters, T[,] or T[][] may be a better fit. A list of lists prioritizes flexibility over compact storage and cache-friendly traversal.
That means the best data structure depends on whether the main requirement is mutability and irregular shape or predictable rectangular access.
Another practical design question is whether missing rows should be represented by empty lists or by absent rows entirely. Making that choice explicit early helps keep indexing and validation logic consistent across the rest of the code.
Common Pitfalls
Assuming List<List<T>> behaves like a dense matrix can lead to unnecessary complexity if the data is actually rectangular.
Reusing the same inner list instance in multiple positions creates shared-state bugs.
Accessing matrix[row][column] without checking row length can throw out-of-range exceptions when rows are ragged.
Summary
- In C#, a list of lists is
List<List<T>>. - It is best for dynamic or ragged nested data.
- Create each inner list separately to avoid accidental reference sharing.
- Use nested iteration or
SelectManydepending on whether you need row structure or a flat view. - Choose a different structure if the data is fixed-size and rectangular.

