The .ToDictionary()
extension will throw an argument exception if we have duplicate keys added to the dictionary.
Ex:
List<int> listOfItems= new List<int>{1,1,2,3,4,4,5}; Dictionary<int, string> dict = listOfItems.ToDictionary(a => a, a => "item " + a); Console.WriteLine(dict.Count);
The above code throws the following exception
System.ArgumentException: An item with the same key has already been added.
In this post, we’ll create an extension method which will ignore duplicate keys from being added to a dictionary.
So, though we add duplicates into the list of items and have it to transform to a dictionary, our extension method should ignore the duplicates and returns a dictionary without duplicates.
First, let’s see what is in the original .ToDictionary()
extension method.
Original ToDictionary extension method source code
public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer) { if (source == null) throw Error.ArgumentNull("source"); if (keySelector == null) throw Error.ArgumentNull("keySelector"); if (elementSelector == null) throw Error.ArgumentNull("elementSelector"); Dictionary<TKey, TElement> d = new Dictionary<TKey, TElement>(comparer); foreach (TSource element in source) d.Add(keySelector(element), elementSelector(element)); return d; }
`.ToDictionary()` extension method is just a foreach over the enumerables. Each item in the list will be iterated and added to the dictionary. The accumulated dictionary is returned in the end.
ToSafeDictionary extension method
To implement .ToSafeDictionary()
extension method, We’ll just extend the original .ToDictionary()
method to have contains check before adding any item to the dictionary. No magic, just a conditional check to ignore the key.
public static Dictionary<TKey, TElement> ToSafeDictionary<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer) { if (source == null) throw new ArgumentException("source"); if (keySelector == null) throw new ArgumentException("keySelector"); if (elementSelector == null) throw new ArgumentException("elementSelector"); Dictionary<TKey, TElement> d = new Dictionary<TKey, TElement>(comparer); foreach (TSource element in source) { if (!d.ContainsKey(keySelector(element))) d.Add(keySelector(element), elementSelector(element)); } return d; }
Note that I’ve used the ArgumentException
when the values for the parameters is null instead of using the original source code Error.ArgumentNull
just to make sure we compile the code in C#.
Now if we run the same example code with .ToSafeDictionary
on the list of items then we should not get any exceptions.
Dictionary<int, string> dict = listOfItems.ToSafeDictionary(a => a, a => "item " + a, null); Console.WriteLine(dict.Count);
References
Karthik is a passionate Full Stack developer working primarily on .NET Core, microservices, distributed systems, VUE and JavaScript. He also loves NBA basketball so you might find some NBA examples in his posts and he owns this blog.
Pingback: URL