Introduction
I often need to search for a specific item inside a list, but as you know, the complexity of List.Find
is O(n). So, if you englobe your find in a foreach
loop, you might risk a serious performance decrease with an O(n²) algorithm.
What I prefer to do is, transform my list to a dictionary because the dictionary[key] is only O(1) thanks to indexing. You can manually transform dictionary to a list through code but .NET Framework provides us with more sophisticated ways today. :)
The ToDictionary Way
public Dictionary<string, string> TransformWithToDictionary()
{
List<string> myList = new List<string>
{
"Brian",
"Leslie",
"Nathan",
"Natalie",
"Dimitry"
};
return myList.ToDictionary(k=>k);
}
Result will be a Dictionary<string, string>
like this:
Dictionary<string, string> result = new Dictionary<string,string>
{
{"Brian", "Brian"},
{"Leslie", "Leslie"},
{"Nathan", "Nathan"},
{"Natalie","Natalie"},
{"Dimitry", "Dimitry"}
};
ToDictionary
method converts List
to Dictionary
while giving you the hand to choose the dictionary key (thanks to the lambda expression).
You need to be careful from raising an exception when you insert an already existing key such as this example:
return myList.ToDictionary(k=>k[0].ToString());
The expected result should be:
Dictionary<string, string> myList = new Dictionary<string,string>
{
{"B", "Brian"},
{"L", "Leslie"},
{"N", "Nathan"},
{"N","Natalie"},
{"D", "Dimitry"}
};
But this can't be realized due to the duplicated "N
" key and will eventually result in an exception saying: an element with the same key already exists in the dictionary.
The Lookup Way
public ILookup<string, string> TransformWithToLookup()
{
List<string> myList = new List<string>
{
"Brian",
"Leslie",
"Nathan",
"Nathan",
"Dimitry"
};
return myList.ToLookup(k => k, v=>v[1].ToString());
}
The lookup mechanism is a bit different though:
- It groups values by keys inside a grouping
- It gives you the hand on what to retrieve from the value through a second lambda expression
The result can be accessed directly through keys:
List<string> tempRes = result["Brian"].ToList();
Or iterated through:
foreach (var item in result)
{
List<string> tempRes = item.ToList();
}
Note that grouping can contain more than one value so if we do:
var temp = res2["Nathan"].ToList();
The expected result would be:
var temp = new List<string> { "a", "a" };
The Linq Way
public Dictionary<string, List<string>> TransformWithLinq()
{
List<string> myList = new List<string>
{
"Brian",
"Leslie",
"Nathan",
"Nathan",
"Dimitry"
};
return myList.GroupBy(k => k, v => v).ToDictionary(g =>g.Key, g=>g.ToList());
}
This way is a combination of Linq methods, let's analyse them one by one:
- The
GroupBy
groups values by keys - The
GroupBy
returns an IEnumerable
of Groupings containing key and its corresponding values - Using the
ToDictionary
way, we get a dictionary of { key, list of values} without worrying about duplicated keys !
Voila:
Dictionary<string, List<string>> result = new Dictionary<string, List<string>>
{
{"Brian", new List<string> {"Brian"}},
{"Leslie", new List<string> {"Leslie"}},
{"Nathan", new List<string> {"Nathan", "Nathan"}},
{"Dimitry", new List<string> {"Dimitry"}},
};
Credits
This tip aims to solve those tiny problems that we rarely care about. It may not be much for some people, but as a person looking to make my code as best as I can, it sure is a great way to save time and performance.