C# Generic SortedList:

A 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. Generic SortedList implements IDictionary<TKey,TValue> & ICollection<KeyValuePair<TKey,TValue>> interfaces so elements can be access by key and index both.

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.

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.

Initialize Generic SortedList:

You can initialize generic SortedList by specifying type for key and value as shown below.

Initialize generic SortedList:

SortedList<int,string> mySortedList = new SortedList<int,string>();

In the above example, mySortedList will store key of int type and value (element) of string type.

Important Properties and Methods of SortedList<TKey, TValue>:

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
void Add(TKey key, TValue value) Add key-value pairs into SortedList<TKey, TValue>.
void Remove(TKey key) Removes element with the specified key.
void RemoveAt(int index) Removes element at the specified index.
bool ContainsKey(TKey key) Checks whether the specified key exists in SortedList<TKey, TValue>.
bool ContainsValue(TValue value) Checks whether the specified key exists in SortedList<TKey, TValue>.
void Clear() Removes all the elements from SortedList<TKey, TValue>.
int IndexOfKey(TKey key) Returns an index of specified key stored in internal array of SortedList<TKey, TValue>.
int IndexOfValue(TValue value) Returns an index of specified value stored in internal array of SortedList<TKey, TValue>
bool TryGetValue(TKey key, out TValue value) 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.

Access SortedList<TKey, TValue>:

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

foreach:

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

Access value of 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 SortedList<TKey, TValue>:

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

Contains(), ContainsKey() and ContainsValue():

The Contains() & ContainsKey() methods are used to determine whether the specified key exists in the SortedList collection or not.

Contains() signature: bool Contains(object key)

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.Contains(2); // returns true
sortedList.Contains(4); // returns true
sortedList.Contains(6); // returns false

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

sortedList.ContainsValue("One"); // returns true
sortedList.ContainsValue("Ten"); // returns false

LINQ:

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

Example: Access SortedList<TKey, TValue> 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: Access SortedList<TKey, TValue> 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

Further Reading:

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.

Learn about Dictionary collection next