List vs Dictionary vs HashSet in C#
In software development, performance isn’t just a luxury — it’s a necessity. As senior developers, we often face the crucial decision of selecting the most appropriate data structure for our tasks. The choice between List<T>, Dictionary<TKey, TValue>, and HashSet<T> can make or break an application’s performance, especially at scale. This article aims to provide you with the insights needed to make informed decisions, backed by performance metrics and real-world scenarios
We’ll explore when to use each, their performance characteristics, and how to optimize them for peak efficiency
LIST<T>
Picture a Swiss Army knife. Versatile, right? That’s our List! It’s the go-to tool for when you need a bit of everything.
well-suited for scenarios requiring ordered collections and frequent positional access
What’s it good for?
Practical Application: To-Do List App
Consider a task management system where order is crucial:
public class Task
{
public string Description { get; set; }
public bool IsCompleted { get; set; }
}
public class ToDoList
{
private List<Task> tasks = new List<Task>();
public void AddTask(string description)
{
tasks.Add(new Task { Description = description, IsCompleted = false });
}
public void CompleteTask(int index)
{
if (index >= 0 && index < tasks.Count)
{
tasks[index].IsCompleted = true;
}
}
public List<Task> GetIncompleteTasks()
{
return tasks.Where(t => !t.IsCompleted).ToList();
}
}
Under the hood, List uses a dynamic array. It’s like a magical expanding suitcase — it grows as you add more items. But here’s the kicker!
when it grows, it doesn’t just add one more slot. it doubles in size! 💨
This means adding items is usually super fast (O(1)), but occasionally when it needs to grow, it takes a bit longer (O(n)). On average, though, it’s still pretty zippy!
so, When to use List<T>?
and, When to think twice?
Dictionary<TKey, TValue>
🪶 Optimizing for Lookup Speed
When rapid key-based retrieval is a priority, Dictionary<TKey, TValue> emerges as a powerful solution.
Need to find something? Zap! You’re there instantly. 🌠
What’s it good for?
Recommended by LinkedIn
Practical Application: User Profile Caching
In a high-traffic application, efficient user profile retrieval is critical. Let’s say we’re building a user profile system for our social media app. We want to access user profiles super fast by their ID.
public class UserProfile
{
public int Id { get; set; }
public string Username { get; set; }
public string Email { get; set; }
}
public class UserProfileCache
{
private Dictionary<int, UserProfile> profileCache = new Dictionary<int, UserProfile>();
public void AddOrUpdateProfile(UserProfile profile)
{
profileCache[profile.Id] = profile;
}
public UserProfile GetProfile(int userId)
{
return profileCache.TryGetValue(userId, out var profile) ? profile : null;
}
public bool ProfileExists(int userId)
{
return profileCache.ContainsKey(userId);
}
}
Dictionary<TKey, TValue> uses a hash table under the hood. Think of it as a super-organized library where every book (value) has a unique call number (key). The librarian (hash function) can tell you exactly where to find any book almost instantly!
enabling O(1) average-case time complexity for key-based operations
so, When to use Dictionary
and, When to think twice
HashSet<T>
🪶 Efficient Uniqueness and Set Operations
Imagine a nightclub where every person must be unique. That’s HashSet. It’s the bouncer that ensures no duplicates get in. 🚫👥
It excels in scenarios where maintaining a collection of unique elements is paramount
What’s it good for?
Practical Application: Unique Identifier Tracking
Let’s build a system to track unique hashtags used in our social media app.
public class HashtagTracker
{
private HashSet<string> uniqueHashtags = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
public bool AddHashtag(string hashtag)
{
return uniqueHashtags.Add(hashtag);
}
public bool HasBeenUsed(string hashtag)
{
return uniqueHashtags.Contains(hashtag);
}
public int UniqueHashtagCount => uniqueHashtags.Count;
public IEnumerable<string> GetCommonHashtags(HashtagTracker other)
{
return uniqueHashtags.Intersect(other.uniqueHashtags, StringComparer.OrdinalIgnoreCase);
}
}
HashSet is built on the same principle as Dictionary<TKey, TValue>, but it only stores keys, no values
so, When to use HashSet
and, When to think twice
check out performance analysis and advanced practices here!