Sorting a Dictionary in place with respect to keys

C#SortingDictionary

C# Problem Overview


I have a dictionary in C# like

Dictionary<Person, int>

and I want to sort that dictionary in place with respect to keys (a field in class Person). How can I do it? Every available help on the internet is that of lists with no particular example of in place sorting of Dictionary. Any help would be highly appreciated!

C# Solutions


Solution 1 - C#

You can't sort a Dictionary<TKey, TValue> - it's inherently unordered. (Or rather, the order in which entries are retrieved is implementation-specific. You shouldn't rely on it working the same way between versions, as ordering isn't part of its designed functionality.)

You can use SortedList<TKey, TValue> or SortedDictionary<TKey, TValue>, both of which sort by the key (in a configurable way, if you pass an IEqualityComparer<T> into the constructor) - might those be of use to you?

Pay little attention to the word "list" in the name SortedList - it's still a dictionary in that it maps keys to values. It's implemented using a list internally, effectively - so instead of looking up by hash code, it does a binary search. SortedDictionary is similarly based on binary searches, but via a tree instead of a list.

Solution 2 - C#

Try using SortedDictionary

Solution 3 - C#

The correct answer is already stated (just use SortedDictionary).

However, if by chance you have some need to retain your collection as Dictionary, it is possible to access the Dictionary keys in an ordered way, by, for example, ordering the keys in a List, then using this list to access the Dictionary. An example...

Dictionary<string, int> dupcheck = new Dictionary<string, int>();

...some code that fills in "dupcheck", then...

if (dupcheck.Count > 0) {
  Console.WriteLine("\ndupcheck (count: {0})\n----", dupcheck.Count);
  var keys_sorted = dupcheck.Keys.ToList();
    keys_sorted.Sort();
  foreach (var k in keys_sorted) {
    Console.WriteLine("{0} = {1}", k, dupcheck[k]);
  }
}

Don't forget using System.Linq; for this.

Solution 4 - C#

Due to this answers high search placing I thought the LINQ OrderBy solution is worth showing:

class Person
{
	public Person(string firstname, string lastname)
	{
		FirstName = firstname;
		LastName = lastname;
	}
	public string FirstName { get; set; }
	public string LastName { get; set; }
}

static void Main(string[] args)
{
	Dictionary<Person, int> People = new Dictionary<Person, int>();

	People.Add(new Person("John", "Doe"), 1);
	People.Add(new Person("Mary", "Poe"), 2);
	People.Add(new Person("Richard", "Roe"), 3);
	People.Add(new Person("Anne", "Roe"), 4);
	People.Add(new Person("Mark", "Moe"), 5);
	People.Add(new Person("Larry", "Loe"), 6);
	People.Add(new Person("Jane", "Doe"), 7);

	foreach (KeyValuePair<Person, int> person in People.OrderBy(i => i.Key.LastName))
	{
		Debug.WriteLine(person.Key.LastName + ", " + person.Key.FirstName + " - Id: " + person.Value.ToString());
	}
}

Output:

Doe, John - Id: 1
Doe, Jane - Id: 7
Loe, Larry - Id: 6
Moe, Mark - Id: 5
Poe, Mary - Id: 2
Roe, Richard - Id: 3
Roe, Anne - Id: 4

In this example it would make sense to also use ThenBy for first names:

foreach (KeyValuePair<Person, int> person in People.OrderBy(i => i.Key.LastName).ThenBy(i => i.Key.FirstName))

Then the output is:

Doe, Jane - Id: 7
Doe, John - Id: 1
Loe, Larry - Id: 6
Moe, Mark - Id: 5
Poe, Mary - Id: 2
Roe, Anne - Id: 4
Roe, Richard - Id: 3

LINQ also has the OrderByDescending and ThenByDescending for those that need it.

Solution 5 - C#

By design, dictionaries are not sortable. If you need this capability in a dictionary, look at SortedDictionary instead.

Solution 6 - C#

While Dictionary is implemented as a hash table, SortedDictionary is implemented as a Red-Black Tree.

If you don't take advantage of the order in your algorithm and only need to sort the data before output, using SortedDictionary would have negative impact on performance.

You can "sort" the dictionary like this:

Dictionary<string, int> dictionary = new Dictionary<string, int>();
// algorithm
return new SortedDictionary<string, int>(dictionary);

Solution 7 - C#

Take a look at SortedDictionary, there's even a constructor overload so you can pass in your own IComparable for the comparisons.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSoulReaverView Question on Stackoverflow
Solution 1 - C#Jon SkeetView Answer on Stackoverflow
Solution 2 - C#Chris OView Answer on Stackoverflow
Solution 3 - C#Steve GreeneView Answer on Stackoverflow
Solution 4 - C#Daniel S. FowlerView Answer on Stackoverflow
Solution 5 - C#Scott DormanView Answer on Stackoverflow
Solution 6 - C#Draex_View Answer on Stackoverflow
Solution 7 - C#Dave DView Answer on Stackoverflow