Hyrial
Hyrial

Reputation: 1888

How to efficiently return the first and last item in a SortedList<> in C#?

My question is like the following question but with SortedList<Tkey, TValue> instead of just the original SortedList.

Return first element in SortedList in C#

There doesn't seem to be a function like GetKey().

Upvotes: 4

Views: 2632

Answers (3)

vladimir
vladimir

Reputation: 15246

Using IEnumerable<>.Last or IEnumerable<>.LastOrDefault methods are efficient just for IList<> values. Let's look at the source code - access to the last item for not IList<> requires iterating through all items.

For more efficiency better to rely on SortedList<>.Keys or SortedList<>.Values properties with type IList<> (https://dotnetfiddle.net/MLmDIL) :

        var sl = new SortedList<string, int>();

        for (var i = 0; i < 50000; i++) {
            sl.Add(i.ToString("X8"), i);
        }       

        Console.WriteLine("SortedList<> is IList<>: " + (sl is IList<KeyValuePair<string, int>>));
        Console.WriteLine("Keys-property in SortedList<> is IList<>: " + (sl.Keys is IList<string>));


        Console.WriteLine("\n\nPerformance measurement - get last Key:");

        var firstKey = sl.First().Key;

        watch.Restart();        
        var lastKey = sl.Last().Key;
        watch.Stop();
        Console.WriteLine("   * Non IList<> access takes {0} (first key: {1}, last key: {2})", watch.Elapsed.TotalMilliseconds, firstKey, lastKey);

        firstKey = sl.Keys.First();

        watch.Restart();        
        lastKey = sl.Keys.Last();
        watch.Stop();
        Console.WriteLine("   * IList<> access takes {0} (first key: {1}, last key: {2})", watch.Elapsed.TotalMilliseconds, firstKey, lastKey);


        Console.WriteLine("\n\nPerformance measurement - get last Value:");

        var firstValue = sl.First().Value;

        watch.Restart();        
        var lastValue = sl.Last().Value;
        watch.Stop();
        Console.WriteLine("   * Non IList<> access takes {0} (first value: {1}, last value: {2})", watch.Elapsed.TotalMilliseconds, firstValue, lastValue);

        firstValue = sl.Values.First();

        watch.Restart();        
        lastValue = sl.Values.Last();
        watch.Stop();
        Console.WriteLine("   * IList<> access takes {0} (first value: {1}, last value: {2})", watch.Elapsed.TotalMilliseconds, firstValue, lastValue);     


        Console.WriteLine("\n\nPerformance measurement - get last Value by Key:");

        watch.Restart();        
        lastKey = sl.Keys.Last();
        lastValue = sl[lastKey];
        watch.Stop();
        Console.WriteLine("   * IDictionary<> access takes {0} (last key: {1}, last value: {2})", watch.Elapsed.TotalMilliseconds, lastKey, lastValue); 

    /*
    Execution result:

SortedList<> is IList<>: False
Keys-property in SortedList<> is IList<>: True


Performance measurement - get last Key:
   * Non IList<> access takes 0.7146 (first key: 00000000, last key: 0000C34F)
   * IList<> access takes 0.0032 (first key: 00000000, last key: 0000C34F)


Performance measurement - get last Value:
   * Non IList<> access takes 0.7366 (first value: 0, last value: 49999)
   * IList<> access takes 0.0003 (first value: 0, last value: 49999)


Performance measurement - get last Value by Key:
   * IDictionary<> access takes 0.0036 (last key: 0000C34F, last value: 49999)
    */

Upvotes: 2

Mohamad Mousheimish
Mohamad Mousheimish

Reputation: 1705

You can simply use list.FirstOrDefault() and list.LastOrDefault().

These two methods will return default(KeyValuePair<TKey,TValue>) if the list is empty.

And it's better to use them because using list.First() and list.Last() will throw error in case the list was empty.

Upvotes: 9

vc 74
vc 74

Reputation: 38179

According to your (not so clear) question, you want to retrieve the keys of the first and last items in the list.

SortedList<TKey, TValue> implements IEnumerable<KeyValuePair<TKey,TValue>> so to do so:

sortedList.FirstOrDefault().Key

and

sortedList.LastOrDefault().Key

will return these keys

Edit: As suggested by @mjwills, using the Keys property is a better idea in terms of performance since it implements IList<TKey> and LastOrDefault is optimized to work on such cases (not fetching the whole collection to get to the last item):

sortedList.Keys.FirstOrDefault()
sortedList.Keys.LastOrDefault()

Upvotes: 7

Related Questions