Sort ListBox or ComboBox items in numeric order in C#

[numeric order]

If you set a ListBox control’s Sorted property to true, the control sorts its contents. Unfortunately it can only sort its contents in alphabetic order. If the items are numeric, that may not be what you want.

This example sorts the items in a ListBox in numeric order. Originally I just wanted to handle items that were numbers, but later I extended the example to order items by the first numeric string they contain. If an item doesn’t contain a numeric value, then it comes at the beginning.

The ListBox and ComboBox controls inherit from ListControl so it would be nice to use a single method to sort either. Unfortunately the two types of controls add their own Items properties rather than inheriting a common property from ListControl so that won’t work.

To work around this, the program uses two short methods named SortListBoxItems and SortComboBoxItems. The following code shows the SortListBoxItems method.

// Sort the items in the ListBox by their numeric values.
private void SortListBoxItems(ListBox lst)
{
    // Get the original items as an array.
    int num_items = lst.Items.Count;
    object[] items = new object[num_items];
    lst.Items.CopyTo(items, 0);

    // Sort them by their contained numeric values.
    items = SortNumericItems(items);

    // Display the results.
    lst.Sorted = false;
    lst.DataSource = items;
}

This code creates an array of object, copies the ListBox control’s items into it, and then calls SortNumericItems to sort them numerically. It then sets the ListBox control’s Sorted property to false so the control doesn’t try to sort the items itself. It then sets the control’s DataSource property to the sorted array so the ListBox displays the items in sorted order.

The SortComboBoxItems method is similar except it works with a ComboBox instead of a ListBox.

The following code shows the SortNumericItems method.

// Sort items by contained numeric values.
private object[] SortNumericItems(object[] items)
{
    // Get the numeric values of the items.
    int num_items = items.Length;
    const string float_pattern = @"-?\d+\.?\d*";
    double[] values = new double[num_items];
    for (int i = 0; i < num_items; i++)
    {
        string match = Regex.Match(
            items[i].ToString(), float_pattern).Value;
        double value;
        if (!double.TryParse(match, out value))
            value = double.MinValue;
        values[i] = value;
    }

    // Sort the items array using the keys to determine order.
    Array.Sort(values, items);
    return items;
}

The code first creates an array of double to hold a value for each of the items. It then loops through the items, converts each into a string, and uses the regular expression method Regex.Match to find the first part of the string that matches the pattern -?\d+\.?\d*. That pattern matches:

  • A dash zero or one times
  • A digit one or more times
  • A decimal point zero or one times
  • A digit zero or more times

The result is a numeric string that can include a negative sign or a decimal point.

After finding the numeric string, if it exists, the code uses double.TryParse to try to parse it. If the value isn’t numeric, then there’s no numeric string in the item so the code uses the value double.MinValue instead to place the item at the beginning of the sorted result.

After generating the numeric values for the items, the method calls Array.Sort to sort the items using the double array to determine their order.

The method finishes by returning the sorted item array.

You can modify the SortNumericItems method if you need to sort items in other ways. For example, if the numeric values might contain currency signs or thousands separators, you should be able to modify the regular expression to get the numeric order that you need.


Download Example   Follow me on Twitter   RSS feed   Donate




This entry was posted in controls, user interface and tagged , , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *