Первый элемент в SortedDictionary?

Существует много, много тем о том, как получить "первый" элемент из Dictionary, и различные ответы о том, почему это не очень хорошая идея, поскольку нет внутреннего порядка. Но у меня SortedDictionary, так что эти аргументы не применимы. Тем не менее, я не могу найти способ получить N-й элемент из SortedDictionary проще, чем из Dictionary.

Вот мой СД:

FRs As SortedDictionary(Of DateTime, ScheduleItem)

Я вижу несколько подсказок, которые я должен уметь делать:

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

Но это неверно в моем коде - он говорит, что у него нет значений по умолчанию и его нельзя проиндексировать. .First и другие параметры, похоже, находятся в LINQ, на который я не могу настроить таргетинг. Так есть ли простой способ получить к нему доступ таким образом?

Примечание: любое предлагаемое решение не должно использовать LINQ, которого нет на многих платформах, отличных от Wintel.


person Maury Markowitz    schedule 28.04.2016    source источник


Ответы (3)


Проблема в том, что SortedDictionary действительно упорядочивается по ключу. Но это не значит, что вы можете получить к нему доступ через index. Итак, если вы не можете использовать LINQ:

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

В противном случае вы могли бы просто использовать First/ FirstOrDefault.

Примечание: поскольку KeyValuePair(Of Tkey, TValue) является структурой, а значит, типом значения, он никогда не бывает null/Nothing. Вы можете проверить наличие пустого словаря таким уродливым способом:

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

Так что гораздо читабельнее использовать If FRs.Count = 0 Then ....


Обновление: если вам просто нужен ключ или значение по заданному индексу, вы можете использовать:

Dim firstSchedule As Date = FRs.Keys(0)

или первый Date в нем:

Dim firstDate As ScheduleItem = FRs.Values(0)

Таким образом, вы могли бы получить оба через индекс даже без LINQ:

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

Отказ от ответственности: согласно мой вопрос здесь это работает, только если вы импортировали System.Linq, тогда Enumerable.ElementAt используется неявно, что перечисляет последовательность для поиска элемента по индексу, если тип не реализует IList(Of T). Так что не используйте его в этом случае.

person Tim Schmelter    schedule 28.04.2016
comment
Хорошо, спасибо, Тим. Опять еще один обдуманный момент. На самом деле, нет никаких причин, по которым они не могли бы сделать это по умолчанию, не так ли? - person Maury Markowitz; 28.04.2016
comment
Это не работает в моем коде, я получаю сообщение об отсутствии значения по умолчанию или индекса. Точнее: «Общедоступные ключи свойств только для чтения перегружаются как SortedDictionary (Of Date, ScheduleItem).KeyCollection» не имеет параметров, и его возвращаемый тип не может быть проиндексирован - person Maury Markowitz; 28.04.2016
comment
... что довольно раздражает при попытке перебрать коллекцию в обратном порядке и удалить дубликаты. - person Maury Markowitz; 28.04.2016
comment
@MauryMarkowitz: странно, ты прав. Но у меня компилируется и работает. Интересно - person Tim Schmelter; 29.04.2016
comment
@MauryMarkowitz: я создал вопрос по этой теме: stackoverflow.com/questions/36933428/ - person Tim Schmelter; 29.04.2016

Linq — это в основном просто набор методов расширения, поэтому вы можете написать собственный:

Imports System
Imports System.Collections.Generic
Imports System.Runtime.CompilerServices

Public Module EnumerableExtensions

    <Extension()> 
    Public Function FirstValue(Of TKey, TValue)(source As SortedDictionary(Of TKey, TValue)) As TValue
        For Each kvp In source
            Return kvp.Value
        Next
        Return Nothing
    End Function

End Module

Public Module Module1
    Public Sub Main()
        Dim a As SortedDictionary(Of string, string) = new SortedDictionary(Of string, string)
        a.Add("foo", "1 - foo")
        a.Add("bar", "2 - bar")
        Console.WriteLine(a.FirstValue())
    End Sub
End Module

Вот пример, работающий в dotnetfiddle.

person Christopher Currens    schedule 28.04.2016

только что реализованный пример ‹Extension()›; добавлено также расширение для доступа к последней записи; вот мой рабочий код:

''' <summary>
''' return the first object of a sortedDictionary
''' </summary>
''' <typeparam name="TKey">Key tpye</typeparam>
''' <typeparam name="TValue">value type</typeparam>
''' <param name="source">dictionary</param>
''' <returns></returns>

<Extension()>
Public Function FirstValue(Of TKey, TValue)(source As SortedDictionary(Of TKey, TValue)) As TValue
    For Each kvp As TValue In source.Values
        Return kvp
    Next
    Return Nothing
End Function
''' <summary>
''' return the last object of a sortedDictionary
''' </summary>
''' <typeparam name="TKey">Key type</typeparam>
''' <typeparam name="TValue"> value type</typeparam>
''' <param name="source"> dictionary</param>
''' <returns>the last object or nothing for an empty dictionary</returns>
<Extension()>
Public Function lastValue(Of TKey, TValue)(source As SortedDictionary(Of TKey, TValue)) As TValue
    Dim lv As TValue = Nothing
    For Each kvp As TValue In source.Values
        lv = kvp
    Next
    Return lv
End Function
person Hans-Dampf    schedule 10.07.2021