0

I have a SortedDictionary:

Dim myFilterItems As SortedDictionary(Of String, FilterItem)
myFilterItems = New SortedDictionary(Of String, FilterItem)(StringComparer.CurrentCultureIgnoreCase)

The FilterItem class is defined like this:

Private Class FilterItem
    Public ValueToSort As Object
    Public IsChecked As Boolean
    Public IsAbsent As Boolean = False
End Class

I need to enumerate my SortedDictionary sorted by the FilterItem.ValueToSort property. With LINQ, it's easy to do - we get the corresponding IEnumerable and then use For Each:

Dim mySortedValueList As IEnumerable(Of KeyValuePair(Of String, FilterItem))
mySortedValueList = From entry In myFilterItems Order By entry.Value.ValueToSort Ascending
For Each entry As KeyValuePair(Of String, FilterItem) In mySortedValueList
    ' ...
Next

How to do that effectively in .NET 2.0?

TecMan
  • 2,743
  • 2
  • 30
  • 64
  • 1
    You don't use SortedDictionary, basically. SortedDictionary is *defined* to sort on keys, not values. – Jon Skeet Mar 11 '15 at 09:35
  • @JonSkeet, I would be glad to use another kind of collection, but I'm doing a lot of work with my SortedDictionary sorted by keys before the task I asked. I use the SortedDictionary.ContainsKey() method to analyze whether a key is already in the dictionary while enumerating 100'000+ rows of raw data. – TecMan Mar 11 '15 at 09:39
  • 2
    That doesn't mean that SortedDictionary is the right answer. You can copy the key/value pairs to a List and then sort the list with a custom comparer, if you want. (Are you *really* tied to .NET 2.0, by the way? I'd be very worried by that, in terms of security updates if nothing else... Mind you, there are LINQ to Objects implementations that work on .NET 2.0, too...) – Jon Skeet Mar 11 '15 at 09:41
  • Yes, I'm really tied to .NET 2.0. The existing code works fine for .NET 3.5+, but now we need to make it work for .NET 2.0 as we are not allowed to upgrade to .NET 3.5 on those pc's. – TecMan Mar 11 '15 at 09:42
  • Then I suggest you use the list approach I suggested before. But I'd be seriously worried about PCs which were told to old, possibly insecure software :( – Jon Skeet Mar 11 '15 at 09:43
  • @JonSkeet, how can I copy a SortedDictionary to a List? Manually, item-by-item?? – TecMan Mar 11 '15 at 09:44
  • Just pass it to the constructor... – Jon Skeet Mar 11 '15 at 09:53
  • @JonSkeet, oh, sorry, yes - we could use the overloaded constructor List (Generic IEnumerable). But will it work much longer than the LINQ query, because we have one extra copy operation for a long list? – TecMan Mar 11 '15 at 09:57
  • How about you try it and see? (Copying 100,000 references really doesn't take long, and LINQ makes internal copies anyway...) – Jon Skeet Mar 11 '15 at 10:01
  • @JonSkeet, I implemented the approach based on List. See my answer to this question - though it could be your answer. – TecMan Mar 11 '15 at 12:44

1 Answers1

0

I rewrote my code using Lists as Jon Skeet suggested. As I can see from my tests, I have the same performance like with the LINQ query - or even 5-10% gain. The new version of code looks like this:

Dim mySortedValueList As New List(Of KeyValuePair(Of String, FilterItem))(myFilterItems)
If iArr <> iGAFMValueType.Text Then
    mySortedValueList.Sort(AddressOf CompareFilterItemsByValuesToSort)
End If

Private Shared Function CompareFilterItemsByValuesToSort(ByVal itemX As KeyValuePair(Of String, FilterItem), ByVal itemY As KeyValuePair(Of String, FilterItem)) As Integer
    Dim myValueX As IComparable = TryCast(itemX.Value.ValueToSort, IComparable)
    Dim myValueY As IComparable = TryCast(itemY.Value.ValueToSort, IComparable)
    If (myValueX Is Nothing) Then
        If (myValueY Is Nothing) Then
            Return 0
        End If
        Return -1
    End If
    If (myValueY Is Nothing) Then
        Return 1
    End If

    Dim myTypeX As Type = myValueX.GetType()
    Dim myTypeY As Type = myValueY.GetType()
    If (myTypeX <> myTypeY) Then
        Return String.CompareOrdinal(myTypeX.Name, myTypeY.Name)
    End If

    Return myValueX.CompareTo(myValueY)
End Function

However, while working on this comparison algorithm, I found that I can't compare values of some numeric types - though they can be compared (for instance, SByte and Double values). BTW, the original LINQ query also fails in this case. But this is another story that continues in this question:

How to compare two numeric values (SByte, Double) stored as Objects in .NET 2.0?

Community
  • 1
  • 1
TecMan
  • 2,743
  • 2
  • 30
  • 64