Search code examples
vb.netsorteddictionary

First item in a SortedDictionary?


There are many, many threads on ways to get the "first" item from a Dictionary, and various answers as to why such a thing is not really a good idea because there's no internal ordering. But mine's a SortedDictionary, so those arguments don't apply. Yet I cannot find a way to get the Nth item from a SortedDictionary any easier than a Dictionary.

Here is my SD:

FRs As SortedDictionary(Of DateTime, ScheduleItem)

I see a few hints that I should be able to do:

If FRs.Count = 1 Then
    FirstFR = FRs.Keys(0)

But that is not valid in my code - it says it has no defaults and cannot be indexed. .First and other options appear to all be in LINQ, which I cannot target. So is there any simple way to access it in this fashion?

Note: any solution offered must not use LINQ, which does not exist on many non-Wintel platforms.


Solution

  • The problem is that a SortedDictionary is indeed ordered by the key. But that does not mean that you can access it via index. So if you can't use LINQ:

    Dim firstFR As KeyValuePair(Of DateTime, ScheduleItem)
    For Each kv In FRs
        firstFR = kv
        Exit For
    Next
    

    Otherwise you could simply use First/ FirstOrDefault.

    Sidenote: since a KeyValuePair(Of Tkey, TValue) is a structure, therefore a value type, it is never null/Nothing. You could check for an empty dictionary in this ugly way:

    If firstFR.Equals(New KeyValuePair(Of DateTime, ScheduleItem))
        Console.WriteLine("Empty dictionary")
    End If 
    

    So it's much more readable to use If FRs.Count = 0 Then ....


    Update: if you just want the key or value at a given index you can use:

    Dim firstSchedule As Date = FRs.Keys(0)
    

    or the first Date in it:

    Dim firstDate As ScheduleItem = FRs.Values(0)
    

    On this way you could actually get both via index even without LINQ:

    Dim firstFR = new KeyValuePair(Of DateTime, ScheduleItem)(FRs.Keys(0), FRs.Values(0))
    

    Disclaimer: according to my question here this works only if you have imported System.Linq, then Enumerable.ElementAt is used implicitly which enumerates a sequence to find an item via index if the type doesn't implement IList(Of T). So don't use it in this case.