Accessing the item at a specified index in a 'SortedSet'

EDIT: An ordinary (unordered) set such as HashSet<T> manages its elements in no particular order. So, the index of a particular element in an unordered set does not carry any particular meaning.

In contrast however, it makes semantic sense to request an element by its position (index) in a SortedSet<T>. Why bother with the overhead of an ordered collection, otherwise?

That said, for a small SortedSet<T> where performance is not a concern (see example below), the Linq extension method Enumerable.ElementAt() provides a convenient means of retrieving an item by its index. However, for a large SortedSet<T> where the runtime performance of retrieving an element is paramount, consider implementing a custom collection as @Nicholas Carey outlines in his answer.


Original Answer:

You can access an item of interest by its index (position) from your SortedSet via the Enumerable.ElementAt<TSource> method:

var item = mySortedSet.ElementAt(index);

Demonstration:

using System;
using System.Collections.Generic;
using System.Linq;

class SortedSetDemo
{
    static void Main(string[] args)
    {
        var words = new string[]
            {"the", "quick", "brown", "fox", "jumps",
             "over", "the", "lazy", "dog"};

        // Create a sorted set.
        var wordSet = new SortedSet<string>();
        foreach (string word in words)
        {
            wordSet.Add(word);
        }

        // List the members of the sorted set.
        Console.WriteLine("Set items in sorted order:");
        int i = 0;
        foreach (string word in wordSet)
        {
            Console.WriteLine("{0}. {1}", i++, word);
        }

        // Access an item at a specified index (position).
        int index = 6;
        var member = wordSet.ElementAt(index);

        Console.WriteLine("\nThe item at index {0} is '{1}'!", index,
                          member);
    }
}

Expected Output:

The set items in sorted order is:
0. brown
1. dog
2. fox
3. jumps
4. lazy
5. over
6. quick
7. the

The item at position 6 is 'quick'!

That's because a SortedSet has the semantics of a set and is not a List-like construct. Consequently, it does not implement IList (which give you the ability to address items by index via the Item property).

As noted by @DavidRR, you could use the Linq extension method Enumerable.ElementAt(). However, since the backing store of a SortedSet is a red-black tree -- a height-balanced binary tree, accessing an element by index via ElementAt() involves a tree walk — O(N), worst case and O(N/2) on the average, to get to the desired item. Pretty much the same as traversing a singly-linked list to access the Nth item.

So...for large sets, performance is likely to be poor.

If what you want is a unique collection that offers array-like semantics, why not roll your own IList<T> implementation that would enforce uniqueness, just as SorteSet<T> does (ignoring adds of elements that already exist in the colleciton). Use a List<T> as the backing store. Maintain it in sorted sequence so you can use a binary search to determine if the element being added already exists. Or, simply subtype List<T> and override the appropriate methods to get the semantics you want.