Question

I have a the need for key value pair that I wish to sort so I decided to use a SortedList instead of a HashTable.

I am adding the data in the order below to my SortedList which is the order I need it in

     Key          | Value
     --------------------------------
 1   "700-800"    | List(Of Object)
 2   "900-1000"   | List(Of Object)
 3   "1100-1200"  | List(Of Object)
 4   "1700-1800"  | List(Of Object)
 5   "1900-2000"  | List(Of Object)

The key is a string and the value is a List of objects. The key is representing a time slot that has been concatenated from two integer values and delimited by "-". "700" as a string was 0700 initially an integer.

e.g.

Dim key As String = slotTimeStart.ToString() & "-" & slotTimeEnd.ToString()

But once these key value pairs are added to the SortedList they appear in the order

 3   "1100-1200"  | List(Of Object)
 4   "1700-1800"  | List(Of Object)
 5   "1900-2000"  | List(Of Object)
 1   "700-800"    | List(Of Object)
 2   "900-1000"   | List(Of Object)

Unfortunately I recieve the times slots as two integer values which cannot be changed.

Is there any way to force a sort on a SortedList? or is this problem because of the way I am storing my key? Is there a better way to store it?

Was it helpful?

Solution

Create a SortedList(Of String, List(Of Object)) but pass in an IComparer(Of String) to the constructor, where the implementation will compare the keys according to the ordering you want.

You'll have to implement that yourself, but it shouldn't be too hard - just split the string by '-', parse both sides with Int32.Parse and react accordingly. You may even not need to worry about the part after the '-', if your key ranges are non-overlapping.

EDIT: Here's a demo. It only prints out the keys, but that's enough to show they're sorted as you want them.

using System;
using System.Collections.Generic;

public class Test
{
    static void Main(string[] args)
    {
        var list = new SortedList<string, int>(new RangeComparer());
        list.Add("900-1000", 10);
        list.Add("1100-1200", 20);
        list.Add("700-800", 30);
        list.Add("1700-18000", 40);
        list.Add("1900-2000", 50);

        foreach (var entry in list)
        {
            Console.WriteLine(entry.Key);
        }
    }
}

public class RangeComparer : IComparer<string>
{
    private static int ParseStartOfRange(string range)
    {
        int hyphenIndex = range.IndexOf('-');
        // Normally do some error checking in case hyphenIndex==-1
        string firstPart = range.Substring(0, hyphenIndex);
        return int.Parse(firstPart);
    }

    public int Compare(string first, string second)
    {
        // In real code you would probably add nullity checks
        int firstStart = ParseStartOfRange(first);
        int secondStart = ParseStartOfRange(second);
        return firstStart.CompareTo(secondStart);
    }
}

OTHER TIPS

It looks like you're sorting it alphabetically instead of numerically. You would have to make your key numeric to get the sort order you're looking for.

Times that are less than 4 digits long need to be prefixed with a zero ('0') to make them the same length as the ones with 4 digits. That way, the standard comparer will compare char 1 of string 1 which will now be a 0 to char 1 of string 2 which will be a 1, and string 1 will come out first.

could the keys be decimal and look like

7.08
9.1
11.12
17.18
19.20

and convert and format to string as needed.

    Dim sl As New SortedList(Of Decimal, Object)
    'sample data
    For x As Integer = 7 To 20 Step 2
        sl.Add(CDec(x + ((x + 1) / 100)), New Object)
    Next

    Dim aKey As Decimal
    Dim slotStart As DateTime = #1:00:00 PM#
    Dim slotEnd As DateTime = #2:00:00 PM#

    aKey = CDec(slotStart.Hour + (slotEnd.Hour / 100))
    sl.Item(aKey) = New Object
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top