views:

2185

answers:

4

Hello

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?

+1  A: 

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.

Cory Larson
Nope, SortedList allows custom sort orders fairly easily.
Jon Skeet
+7  A: 

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);
    }
}
Jon Skeet
Thanks JonAre you meaning that when i am adding the key as specified in the post above that i do the following when adding it to the SortedListsortedlist.Add(key.ToString(New Comparer(implemtation here), List(Of Object))As i have never used IComparer could you please provide an example?
w4ymo
No - you supply the IComparer(T) when you create the SortedList. Follow the link I supplied for the word "constructor" :) I can't provide an example right now as I need to cook some dinner - and my VB is horrible. Would you be able to follow a C# example?
Jon Skeet
Hey Jon, didn't realise there was links I am still new to the layout of stack overflow :) yes that would be great I am a c# programmer by trade just at a company that needs vb.net
w4ymo
Thanks Jon, will try this out tomorrow, now i must sleep
w4ymo
A: 

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
dbasnett
+1  A: 

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.