C# - SortedList<TKey, TValue>

The generic SortedList SortedList<TKey, TValue> represents a collection of key-value pairs that are sorted by key based on associated IComparer<T>. A SortedList collection stores key and value pairs in ascending order of key by default.

C# includes two type of SortedList, generic SortedList and non-generic SortedList. Generic SortedList denotes with angel bracket: SortedList<TKey,TValue> where TKey is for type of key and TValue is for type of value. Non-generic type do not specify the type of key and values.

The following diagram illustrates the generic SortedList hierarchy.

generic sortedlist C#

Internally, SortedList maintains a two object[] array, one for keys and another for values. So when you add key-value pair, it does binary search using key to find an appropriate index to store a key and value in respective arrays. It also re-arranges the elements when you remove the elements from it.

You can instantiate SortedList<TKey, TValue> by specifying type for key and value, as shown below.

Example: Instantiate Generic SortedList
SortedList<int, string> mySortedList = new SortedList<int,string>();

In the above example, mySortedList will store the keys of int type and the values of string type.

Important Properties and Methods of Generic SortedList

Property Description
Capacity Gets or sets the number of elements that the SortedList<TKey,TValue> can store.
Count Gets the total number of elements exists in the SortedList<TKey,TValue>.
IsReadOnly Returns a boolean indicating whether the SortedList<TKey,TValue> is read-only.
Item Gets or sets the element with the specified key in the SortedList<TKey,TValue>.
Keys Get list of keys of SortedList<TKey,TValue>.
Values Get list of values in SortedList<TKey,TValue>.
Method Description
Add Add key-value pairs into SortedList<TKey, TValue>.
Remove Removes element with the specified key.
RemoveAt Removes element at the specified index.
ContainsKey Checks whether the specified key exists in SortedList<TKey, TValue>.
ContainsValue Checks whether the specified key exists in SortedList<TKey, TValue>.
Clear Removes all the elements from SortedList<TKey, TValue>.
IndexOfKey Returns an index of specified key stored in internal array of SortedList<TKey, TValue>.
IndexOfValue Returns an index of specified value stored in internal array of SortedList<TKey, TValue>
TryGetValue Returns true and assigns the value with specified key, if key does not exists then return false.

Add Elements into SortedList

Use the Add() method to add key value pairs into a SortedList. The key cannot be null, but the value can be null. Also, the datatype of key and value must be same as specified, otherwise it will give compile time error.

Add() method signature: void Add(TKey key, TValue value)

The following example shows how to add key-value pair in the generic SortedList collection.

Example:Add Elements into SortedList<TKey, TValue>
SortedList<int,string> sortedList1 = new SortedList<int,string>();
sortedList1.Add(3, "Three");
sortedList1.Add(4, "Four");
sortedList1.Add(1, "One");
sortedList1.Add(5, "Five");
sortedList1.Add(2, "Two");

SortedList<string,int> sortedList2 = new SortedList<string,int>();
sortedList2.Add("one", 1);
sortedList2.Add("two", 2);
sortedList2.Add("three", 3);
sortedList2.Add("four", 4);
// Compile time error: cannot convert from <null> to <int>
// sortedList2.Add("Five", null);
    
SortedList<double,int?> sortedList3 = new SortedList<double,int?>();
sortedList3.Add(1.5, 100);
sortedList3.Add(3.5, 200);
sortedList3.Add(2.4, 300);
sortedList3.Add(2.3, null);
sortedList3.Add(1.1, null);

SortedList collection sorts the elements everytime you add the elements. So if you debug the above example, you will keys in ascending order even if they are added randomly. The following image shows SortedList in debug view.

SortedList<TKey, TValue> in debug view

As you can see in the above image, sortedList1 stores key-value pairs in ascending order of key and sortedList2 stores items in alphabetical order of key even if they are not added in that ordered. sortedList3 includes nullable int so that it includes null as a value.

Key/value pairs can also be added using object-initializer syntax, as shown below.

Example: Initialize SortedList<TKey, TValue>
SortedList<int,string> sortedList1 = new SortedList<int,string>()
                                    {
                                        {3, "Three"},
                                        {4, "Four"},
                                        {1, "One"},
                                        {5, "Five"},
                                        {2, "Two")}
                                    };

Accessing Generic SortedList

The SortedList can be accessed by the index or key. Unlike other collection types, Indexer of SortedList requires key and returns value for that key. However, please make sure that key exists in the SortedList, otherwise it will throw KeyNotFoundException.

Example: Access SortedList<TKey, TValue> using indexer
SortedList<string,int> sortedList2 = new SortedList<string,int>();
sortedList2.Add("one", 1);
sortedList2.Add("two", 2);
sortedList2.Add("three", 3);
sortedList2.Add("four", 4);

Console.WriteLine(sortedList2["one"]);
Console.WriteLine(sortedList2["two"]);
Console.WriteLine(sortedList2["three"]);

//Following will throw runtime exception: KeyNotFoundException
Console.WriteLine(sortedList2["ten"]);
Output:
1
2
3

Keys and Values indexers can use the access key and value of SortedList using for loop as shown below:

Example: Access Key and Value using indexer
SortedList<string,int> sortedList2 = new SortedList<string,int>();
sortedList2.Add("one", 1);
sortedList2.Add("two", 2);
sortedList2.Add("three", 3);
sortedList2.Add("four", 4);

for (int i = 0; i < sortedList2.Count; i++)
{
    Console.WriteLine("key: {0}, value: {1}", sortedList2.Keys[i], sortedList2.Values[i]);
}
Output:
key: four, value: 4
key: one, value: 1
key: three, value: 3
key: two, value: 2

Accessing Elements using foreach loop

The foreach statement in C# can be used to access the SortedList collection. SortedList element includes both key and value pair. so, the type of element would be KeyValuePair structure rather than type of key or value.

foreach statement to access generic SortedList:
SortedList<string,int> sortedList2 = new SortedList<string,int>();
sortedList2.Add("one", 1);
sortedList2.Add("two", 2);
sortedList2.Add("three", 3);
sortedList2.Add("four", 4);

foreach(KeyValuePair<string,int> kvp in sortedList2 )
    Console.WriteLine("key: {0}, value: {1}", kvp.Key , kvp.Value );
Output:
key: four, value: 4
key: one, value: 1
key: three, value: 3
key: two, value: 2

Accessing key

If you are not sure that particular key exists or not than use TryGetValue method to retrieve the value of specified key. If key doesn't exists than it will return false instead of throwing exception.

Example: TryGetValue
SortedList<string,int> sortedList2 = new SortedList<string,int>();
sortedList2.Add("one", 1);
sortedList2.Add("two", 2);
sortedList2.Add("three", 3);
sortedList2.Add("four", 4);

int val;

if (sortedList2.TryGetValue("ten",out val))
    Console.WriteLine("value: {0}", val);
else
    Console.WriteLine("Key is not valid.");

if (sortedList2.TryGetValue("one",out val))
    Console.WriteLine("value: {0}", val);
Output:
Key is not valid.
value: 1

Remove Elements from Generic SortedList

Use the Remove(key) and RemoveAt(index) methods to remove values from a SortedList.

Remove() signature: bool Remove(TKey key)

RemoveAt() signature: void RemoveAt(int index)

Example: Remove Elements
SortedList<string,int> sortedList2 = new SortedList<string,int>();
sortedList2.Add("one", 1);
sortedList2.Add("two", 2);
sortedList2.Add("three", 3);
sortedList2.Add("four", 4);
    
sortedList2.Remove("one");//removes the element whose key is 'one'
sortedList2.RemoveAt(0);//removes the element at zero index i.e first element: four

foreach(KeyValuePair<string,int> kvp in sortedList2 )
    Console.WriteLine("key: {0}, value: {1}", kvp.Key , kvp.Value );
Output:
key: three, value: 3
key: two, value: 2

ContainsKey() and ContainsValue()

The ContainsKey() checks whether the specified key exists in the SortedList or not.

ContainsKey() signature: bool ContainsKey(object key)

The ContainsValue() method determines whether the specified value exists in the SortedList or not.

ContainValue() signature: bool ContainValue(object value)

Example: Contain()
SortedList<string,int> sortedList = new SortedList<string,int>();
sortedList.Add("one", 1);
sortedList.Add("two", 2);
sortedList.Add("three", 3);
sortedList.Add("four", 4);
sortedList.Add("five", 5);
    
sortedList.ContainsKey("One"); // returns true
sortedList.ContainsKey("Ten"); // returns false

sortedList.ContainsValue(2); // returns true
sortedList.ContainsValue(6); // returns false

Accessing SortedList using LINQ

You can use LINQ query syntax or method syntax to access SortedList collection using different criterias.

Example: Access SortedList using LINQ Method Syntax
SortedList<string,int> sortedList = new SortedList<string,int>();
sortedList.Add("one", 1);
sortedList.Add("two", 2);
sortedList.Add("three", 3);
sortedList.Add("four", 4);
sortedList.Add("five", 5);

var result =  sortedList.Where(kvp => kvp.Key == "two").FirstOrDefault();
    
Console.WriteLine("key: {0}, value: {1}", result.Key, result.Value);
Example: Accessing Generic SortedList using LINQ Query Syntax
SortedList<string,int> sortedList = new SortedList<string,int>();
sortedList.Add("one", 1);
sortedList.Add("two", 2);
sortedList.Add("three", 3);
sortedList.Add("four", 4);
sortedList.Add("five", 5);

var query = from kvp in sortedList
                where kvp.Key == "two"
                select kvp;

var result = query.FirstOrDefault();

Console.WriteLine("key: {0}, value: {1}", result.Key, result.Value);
Output:
key: two, value: 2
Points to Remember :
  1. C# has a generic and non-generic SortedList.
  2. SortedList stores the key-value pairs in ascending order of the key. The key must be unique and cannot be null whereas value can be null or duplicate.
  3. Generic SortedList stores keys and values of specified data types. So no need for casting.
  4. Key-value pair can be cast to a KeyValuePair<TKey,TValue>.
  5. An individual value can be accessed using an indexer. SortedList indexer accepts key to return value associated with it.