LogIn
I don't have account.

Collections in C#

DevSniper

181 Views

#language-concepts

In C#, a collection is a group of related objects that can be easily managed together. Collections are widely used to store, delete, update , retrieve, search, sort data efficiently.

Unlike arrays, collections are dynamic in nature meaning they can automatically grow or shrink as you add or remove elements.

What Are Collections in C#?

A collection in C# represents a container that holds multiple elements, such as numbers, strings or custom objects. Collections make it easier to handle groups of data without worrying about manual resizing or indexing.

Types of Collections in C#

1. System.Collections.Generic classes

2. System.Collections classes (Now deprecated)

3. System.Collections.Concurrent Classes

1. System.Collections.Generic classes

1. List<T>

List<T> is a resizable array that allows random access via an index. It automatically grows in size as new elements are added.

Key Features
  • Stores elements sequentially like an array.
  • Allows index-based access.
  • Automatically resizes as needed.
  • Supports methods like Add(), Remove(), Insert(), Sort(), Find() etc.
When to use
  • Use List<T> when you need a flexible, indexable, and resizable collection similar to arrays.
2. Stack<T> : Last In, First Out (LIFO)

Stack<T> represents a LIFO collection where the last element added is the first one removed. It is useful for scenarios like expression evaluation, undo/redo operations or recursive algorithms.

Key Methods
  • Push(item) : Adds an element to the top.
  • Pop() : Removes and returns the top element.
  • Peek() : Returns the top element without removing it.
When to use
  • Use Stack<T> when you need to process elements in reverse order of insertion.
3. Queue<T> : First In, First Out (FIFO)

Queue<T> implements a First-In, First-Out (FIFO) collection. The first element enqueued (added) is the first one to be dequeued (removed). It’s ideal for scenarios like scheduling, buffering, breadth-first traversal, messaging systems or any workflow where order matters and you process items in the arrival sequence.

Key Methods & Behavior
  • Enqueue(T item) : adds an item to the back of the queue.
  • Dequeue() : removes and returns the item from the front of the queue.
  • Peek() : returns the front item without removing it.
  • Count property : gives the number of elements
When to use
  • Use Queue<T> when you need to process elements in the order they arrive.
4. LinkedList<T> : Doubly Linked List

LinkedList<T> stores items as nodes connected by links. Each node holds a Value plus references to both the previous and next node, making it a doubly‐linked list.

Key Features
  • Efficient insertions/removals anywhere : You can insert or remove nodes in constant time O(1) when you already have a reference to the node.
  • Slower for random access : There is no indexer (list[i]) for fast direct access. To get the n-th element, traversal from a starting node must occur, costing O(n).
  • Count is O(1) : The Count property is maintained internally and returns in constant time.
  • Node structure : Each item is wrapped in a LinkedListNode<T> which links to Previous and Next nodes.
  • Memory overhead : Because each node stores two pointers (prev, next), a LinkedList<T> typically has more memory overhead compared to a List<T> of the same number of elements.
When to use
  • Use LinkedList<T> when you frequently insert or remove elements in the middle of the collection.
  • You do not need fast random indexing access.
5. HashSet<T> : Unique Unordered Collection

HashSet<T> stores only unique elements. It uses hashing internally to provide very fast lookups, making it ideal for membership checks, deduplication and set operations.

Key Features
  • No duplicates allowed : Attempting to add an element that’s already present returns false and does not change the set.
  • Unordered collection : It does not preserve insertion order. The internal ordering is based on hashing.
  • Average O(1) for Add, Remove, Contains : These operations usually run in constant time, making HashSet<T> very efficient for lookups.
  • Mathematical set operations built-in : Methods like UnionWith, IntersectWith, ExceptWith, SymmetricExceptWith and others are supported
  • Capacity auto-scaling : The internal structure expands automatically as more elements are added
When to use
  • Use HashSet<T> when you want to store unique items and perform fast lookups.
  • You don’t care about ordering or indexing of items.
6. SortedSet<T> : Unique and Sorted Collection

SortedSet<T> is a collection that stores unique elements in a sorted order. It is implemented using a balanced binary search tree (red-black tree), which provides efficient insertion, deletion and search operations. This class is part of the System.Collections.Generic namespace and implements the ISet<T> interface.

Key Features
  • Unique and Sorted: Automatically stores elements without duplicates in sorted order.
  • Set Operations: Supports mathematical operations such as UnionWith, IntersectWith and ExceptWith.
  • Optimal Performance: Add(), Remove() and Contains() operations have O(log n) time complexity, where n is the number of elements in the set.
  • Custom Sorting: Allows specifying a custom comparer to define the sorting order.
  • Efficient Range Queries: Provides methods like GetViewBetween() to efficiently retrieve subsets of elements within a specified range.
When to use
  • You need a collection that maintains elements in a sorted order.
  • You require uniqueness of elements without duplicates.
  • You want to perform efficient set operations like union, intersection and difference.
  • You need to efficiently retrieve subsets of elements within a specified range.
7. Dictionary<TKey, TValue> : Key-Value Store

Dictionary<TKey, TValue> is a generic collection in C# that stores data as key-value pairs. It utilizes hashing to provide fast lookups, making it ideal for scenarios where quick data retrieval is essential.

Key Features
  • Unique Keys: Each key must be unique within the dictionary. Attempting to add a duplicate key will throw an ArgumentException.
  • Value Types: Values can be of any type and can be duplicated. Only keys are required to be unique.
  • Fast Lookups: Operations like Add(), Remove() and ContainsKey() have an average time complexity of O(1), thanks to the underlying hash table implementation.
  • Safe Retrieval: Use TryGetValue() to safely retrieve values without throwing exceptions if the key doesn't exist.
  • Enumerator Support: Supports enumeration over key-value pairs, allowing iteration through the dictionary.
When to use
  • You need to store data with a unique identifier (key) and associated value.
  • Fast retrieval, insertion and deletion operations are required.
  • You need to perform operations like checking for the existence of a key or removing key-value pairs efficiently.
8. SortedDictionary<TKey, TValue> : Sorted Key-Value Pairs

SortedDictionary<TKey, TValue> is a generic collection in C# that stores key-value pairs in sorted order based on the keys. It is implemented using a balanced binary search tree (red-black tree), which ensures that operations like insertion, deletion and lookup are efficient.

Key Features
  • Sorted Order : Elements are automatically sorted by key in ascending order. You can specify a custom comparer to define the sorting order.
  • Unique Keys : Each key must be unique within the dictionary. Attempting to add a duplicate key will throw an ArgumentException.
  • Fast Operations: Operations like Add(), Remove() and ContainsKey() have an average time complexity of O(log n), thanks to the underlying red-black tree implementation.
  • Enumerator Support : Supports enumeration over key-value pairs, allowing iteration through the dictionary in sorted order.
  • Capacity Auto-Scaling : The internal structure expands automatically as more elements are added.
When to use
  • You need a collection that maintains elements in a sorted order based on the keys.
  • Fast retrieval, insertion and deletion operations are required.
  • You need to perform operations like checking for the existence of a key or removing key-value pairs efficiently.
9. SortedList<TKey, TValue> : Sorted and Indexed Dictionary

SortedList<TKey, TValue> is a generic collection in C# that stores key-value pairs in sorted order based on the keys. Unlike SortedDictionary<TKey, TValue>, it allows index-based access to elements, providing efficient retrieval by both key and index.

Key Features
  • Sorted Order : Elements are automatically sorted by key in ascending order. You can specify a custom comparer to define the sorting order.
  • Unique Keys : Each key must be unique within the list. Attempting to add a duplicate key will throw an ArgumentException.
  • Efficient Index Access : Provides fast access to elements by index, similar to a list. This is not available in SortedDictionary<TKey, TValue>
  • Memory Efficiency : Uses less memory compared to SortedDictionary<TKey, TValue>, making it suitable for scenarios with limited memory resources.
  • Slower Insertions : Insertion and removal operations are slower compared to SortedDictionary<TKey, TValue> due to the need to maintain sorted order.
When to use
  • You need a collection that maintains elements in a sorted order based on the keys.
  • When you need a sorted dictionary with index-based access.
  • Insertion and removal operations are infrequent or can tolerate slower performance.

Summary Table

Class Type Ordering Duplicates Access Speed Common Use
List Linear Ordered Allowed Fast (index) Dynamic arrays
Stack LIFO Ordered Allowed Fast Undo operations
Queue FIFO Ordered Allowed Fast Task scheduling
LinkedList Linked nodes Ordered Allowed Medium Frequent insert/remove
HashSet Hash-based Unordered ❌ Not Allowed Very Fast Unique items
SortedSet Tree-based Sorted ❌ Not Allowed Fast Sorted unique data
Dictionary Hash-based Unordered Key ❌ duplicate Very Fast Key-value storage
SortedDictionary Tree-based Sorted Key ❌ duplicate Fast Sorted key-value
SortedList Array-based Sorted Key ❌ duplicate Fast (index access) Sorted key-value with index

Internal Working and Performance of Generic Collections in C#

The following table summarizes the internal data structure, time complexity (Big-O) and performance characteristics for access, insertion, deletion and lookup operations of all major collections in the System.Collections.Generic namespace.

Collection Internal Data Structure Access Insert Remove Search / Lookup Ordering Duplicates Remarks / Internal Behavior
List Dynamic Array O(1) (by index) O(1)* (Amortized) / O(n)** O(n) O(n) Ordered (by index) Allowed Internally backed by a resizable array. Capacity doubles when exceeded. Fast random access but costly mid-insertions/removals due to element shifting.
LinkedList Doubly Linked List O(n) O(1)** (with node reference) / O(n)** (without) O(1)** (with node reference) / O(n)** (without) O(n) Ordered (by insertion) Allowed Each node holds references to Next and Previous. Efficient for frequent insertions/removals but slower lookups. No indexing support.
Stack Dynamic Array O(n)** (no direct index access) O(1)** (Push) O(1)** (Pop) O(n)** LIFO Allowed Backed by an internal array. Expands automatically like List. Only top element accessible (Peek, Pop, Push).
Queue Circular Buffer (Array) O(n)** (no direct index access) O(1)** (Enqueue) O(1)** (Dequeue) O(n)** FIFO Allowed Uses a circular array buffer to efficiently manage enqueue and dequeue without shifting all elements. Automatically resizes when full.
HashSet Hash Table O(1)** (average) / O(n)** (worst) O(1)** (average) O(1)** (average) O(1)** (average) Unordered Not Allowed Uses hash codes to manage buckets for fast lookups. Collision handled via chaining. Ideal for checking existence and maintaining unique items.
SortedSet Self-Balancing Binary Search Tree (Red-Black Tree) O(log n) O(log n) O(log n) O(log n) Sorted (ascending by default) Not Allowed Elements kept sorted automatically. Maintains balance to ensure logarithmic performance. Ideal for range queries and sorted views.
Dictionary Hash Table O(1)** (average) / O(n)** (worst) O(1)** (average) O(1)** (average) O(1)** (average) Unordered Key duplicates not allowed Uses a hash function to map keys to buckets. Provides fast key-based access. Collisions handled via chaining. Key uniqueness enforced.
SortedDictionary Red-Black Tree O(log n) O(log n) O(log n) O(log n) Sorted by Key Key duplicates not allowed Stores key-value pairs sorted by keys. Maintains tree balance for consistent logarithmic performance. Slightly higher memory usage than Dictionary.
SortedList Two Parallel Arrays (Keys + Values) O(log n)** (binary search by key) / O(1)** (by index) O(n)** (shifting on insert) O(n)** (shifting on remove) O(log n)** Sorted by Key Key duplicates not allowed Internally maintains two arrays, one for keys, one for values, sorted by key. Low memory overhead but costly insertion/removal for large datasets.

2. System.Collections classes

ArrayList
Stack
Queue
Hashtable

3. System.Collections.Concurrent classes

BlockingCollection
ConcurrentBag
ConcurrentStack
ConcurrentQueue
ConcurrentDictionary
Partitioner
OrderablePartitioner