Results 1 to 18 of 18

Thread: [RESOLVED] Sorting a ListBox by ItemData?

  1. #1

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2007
    Posts
    1,072

    Resolved [RESOLVED] Sorting a ListBox by ItemData?

    I have a listbox that looks like this:



    I need it to be sorted by ItemData.

    So the list will then look like:



    I will rate good answers.

    -Zach

  2. #2
    PowerPoster
    Join Date
    Nov 2002
    Location
    Manila
    Posts
    7,629

    Re: Sorting a ListBox by ItemData?

    If list of values comes from a database then sort using SQL ORDER BY clause before filling up the listbox.

    You can also consider changing the GUI to use multi-column controls such as the listview control.

  3. #3
    VB For Fun Edgemeal's Avatar
    Join Date
    Sep 2006
    Location
    WindowFromPoint
    Posts
    4,255

    Re: Sorting a ListBox by ItemData?

    You could do it like this, but its not very fast with listboxes that have 1000s of items.
    EDIT Updated, Thanks Ellis.
    Code:
    Private Sub SortListByItemData2(Lst As ListBox)
        ' // Sort ListBox By ItemData //
        Dim lData() As Long
        Dim sData() As String
        Dim lTmp As Long
        Dim sTmp As String
        Dim i As Integer, j As Integer, Count As Integer
        ' Get list count
        Count = Lst.ListCount - 1
        If Count < 1 Then Exit Sub ' Nothing to sort
        ' Dimension arrays
        ReDim lData(Count)
        ReDim sData(Count)
        ' Put list and item data into arrays
        For i = 0 To Count
            lData(i) = Lst.ItemData(i)
            sData(i) = Lst.List(i)
        Next i
        ' Sort list by itemdata values
        For i = 0 To Count
            For j = Count To i + 1 Step -1
                If lData(i) > lData(j) Then ' Sort Ascending
                    lTmp = lData(j) ' swap item data
                    lData(j) = lData(i)
                    lData(i) = lTmp
                    sTmp = sData(j) ' swap list data
                    sData(j) = sData(i)
                    sData(i) = sTmp
                End If
            Next j
        Next i
        ' Copy sorted data back to listbox
        Lst.Clear
        For i = 0 To Count
            Lst.AddItem sData(i)
            Lst.ItemData(i) = lData(i)
        Next i
    End Sub
    Last edited by Edgemeal; Oct 21st, 2008 at 02:12 PM. Reason: Updated

  4. #4
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: Sorting a ListBox by ItemData?

    Does that sorting algorithm have a name or did you make it up from scratch?
    Last edited by Ellis Dee; Oct 20th, 2008 at 07:31 PM.

  5. #5
    VB For Fun Edgemeal's Avatar
    Join Date
    Sep 2006
    Location
    WindowFromPoint
    Posts
    4,255

    Re: Sorting a ListBox by ItemData?

    Quote Originally Posted by Ellis Dee
    Does that sorting algorithm have a name or did you make it up from scratch?
    I got the basic code from someone named MrMac awhile back (not sure if he is on this forum or not),

    Code:
        For i = 0 To UBound(d) - 1
            For j = i + 1 To UBound(d) - 1
                If d(i) > d(j) Then
                    Dtmp = d(j)
                    d(j) = d(i)
                    d(i) = Dtmp
    
                End If
            Next j
        Next i
    was posted for sorting numbers in a listbox since VBs listbox sort falls short for sorting numbers, so I just expanded it for this sort by item data usage.

  6. #6
    PowerPoster techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,687

    Re: Sorting a ListBox by ItemData?

    bubble sort... wow.... great for short lists.... sucks like a Hoover for larger items....

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  7. #7
    VB For Fun Edgemeal's Avatar
    Join Date
    Sep 2006
    Location
    WindowFromPoint
    Posts
    4,255

    Re: Sorting a ListBox by ItemData?

    Ya it's slow, but OK if you only have like 1000 items max. I've made a couple vitural listbox classes that use moded versions of Ellis's QuickSort posted in the code bank, that code leaves smoke trails behind its so fast!

  8. #8
    PowerPoster
    Join Date
    Nov 2002
    Location
    Manila
    Posts
    7,629

    Re: Sorting a ListBox by ItemData?

    True, but that is just additional code that has to be maintained if application needs to be enhanced, e.g. GUI changes. I lean towards using a listview or something that doesn't tie sorting to the GUI too much, e.g. sorting before displaying using SQL if data comes from database.

    For most business applications, normal speed is acceptable in order to gain RAD, maintainability, etc-ility.
    Last edited by leinad31; Oct 20th, 2008 at 08:50 PM.

  9. #9
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: Sorting a ListBox by ItemData?

    Quote Originally Posted by techgnome
    bubble sort... wow.... great for short lists.... sucks like a Hoover for larger items....

    -tg
    No, it isn't bubble sort. The first tipoff is that you can't write a bubblesort using a For...Next loop, because the number of passes needed is indeterminate. As a quick example, bubble sort is the fastest algorithm there is on an already ordered list, having only to make N comparisons before quitting. The above algorithm looks like it needs 1+2+3+...+N comparisons on an ordered list, which would be much slower.

    It's some kind of selection sort hybrid. On a randomized list, it will blow bubblesort out of the water, much like selection sort. That doesn't mean it's fast, though; you have to work at it to come up with an algorithm as slow as bubble sort.

    The defining characteristic of bubble sort is that it only swaps immediate neighbors. This is what makes it a stable algorithm. Edgemeal's algorithm swaps elements at any distance from each other, making it unstable.

    The algorithm's control structure is identical to selection sort, it is conceptually very similar to gnome sort, and in practice it behaves similarly to heap sort. I have run across quite a few comparison sorts, and this is a new one to me. I threw it into my sorting program to see it in action. Here is is (labeled as Bubble sort) partway through. You can see how it stacks up all the larger elements toward the front of the list much like heap sort.

    Note that while it seems to be keeping pace with selection sort, this means it is much slower. It starts off quickly and slows down as it progresses like gnome (insertion) sort, opposite of selection sort which starts off slow and speeds up as it progresses. You can tell it gets slower as it progresses because it's basically doing an inverse-insertion.
    Attached Images Attached Images  

  10. #10
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: Sorting a ListBox by ItemData?

    If you reverse the direction of the interior loop it would make it more efficient.
    Code:
        ' sort list by itemdata values
        For i = 0 To Count
            For j = Count To i + 1 Step -1
                If iData(i) > iData(j) Then ' sort acsending
                    dTmp = iData(j) ' swap item data
                    iData(j) = iData(i)
                    iData(i) = dTmp
                    sTmp = lData(j) ' swap list data
                    lData(j) = lData(i)
                    lData(i) = sTmp
                End If
            Next j
        Next i
    Note how much more order is being produced in the early stages of processing.
    Attached Images Attached Images  

  11. #11
    VB For Fun Edgemeal's Avatar
    Join Date
    Sep 2006
    Location
    WindowFromPoint
    Posts
    4,255

    Re: Sorting a ListBox by ItemData?

    Quote Originally Posted by Ellis Dee
    If you reverse the direction of the interior loop it would make it more efficient.
    That crossed my mind but I didn't think it would make much of a difference if any (too lazy to test), but it it does!
    EDIT: Changes made to original post.
    Last edited by Edgemeal; Oct 21st, 2008 at 02:13 PM.

  12. #12
    PowerPoster Code Doc's Avatar
    Join Date
    Mar 2007
    Location
    Omaha, Nebraska
    Posts
    2,354

    Re: Sorting a ListBox by ItemData?

    This thread intrigues me to the extent that you have to wonder what sorting routine that the standard list box uses when the Sort option is set to true. If anyone knows, please holler.

    That being said, I wonder if OP might want to consider using an invisible Sorted list box to temporarily hold all the data with the item data switched to the left within the string. Then read that back out and drop the sorted contents into an unsorted, visible list box with the item data switched back to the right.

    That procedure even eliminates the requirement of an array.
    Last edited by Code Doc; Oct 21st, 2008 at 01:30 PM.
    Doctor Ed

  13. #13
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: Sorting a ListBox by ItemData?

    The sorting speed could be improved a lot if the strings weren't copied as the sorting progresses. I suggest a third array that just holds the information of the new indexes.


    Alternatively you can also do evil hacks that are slightly lengthy for the purpose:
    Code:
    Option Explicit
    
    ' ProcedureReplace
    Private Declare Function CloseHandle Lib "Kernel32" (ByVal hObject As Long) As Long
    Private Declare Sub CopyMemory Lib "Kernel32" Alias "RtlMoveMemory" (ByRef lpvDest As Any, ByRef lpvSrc As Any, ByVal cbLen As Long)
    Private Declare Function GetCurrentProcessId Lib "Kernel32" () As Long
    Private Declare Function OpenProcess Lib "Kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
    Private Declare Function WriteProcessMemory Lib "Kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
    
    Private Function InIDE(Optional IDE) As Boolean
        If IsMissing(IDE) Then Debug.Assert Not InIDE(InIDE) Else IDE = True
    End Function
    Private Sub ProcedureReplace(ByVal AddressOfDest As Long, ByVal AddressOfSrc As Long)
        Dim lngJMPASM(1) As Long, lngBytesWritten As Long, lngProcessHandle As Long
        ' get a handle for current process
        lngProcessHandle = OpenProcess(&H1F0FFF, 0&, GetCurrentProcessId)
        ' if failed, we can't do anything
        If lngProcessHandle = 0 Then Exit Sub
        ' check if we are in the IDE
        If InIDE Then
            ' get the real locations of the procedures
            CopyMemory AddressOfDest, ByVal AddressOfDest + &H16&, 4&
            CopyMemory AddressOfSrc, ByVal AddressOfSrc + &H16&, 4&
        End If
        ' set ASM JMP
        lngJMPASM(0) = &HE9000000
        ' set JMP parameter (how many bytes to jump)
        lngJMPASM(1) = AddressOfSrc - AddressOfDest - 5
        ' replace original procedure with the JMP
        WriteProcessMemory lngProcessHandle, ByVal AddressOfDest, ByVal VarPtr(lngJMPASM(0)) + 3, 5, lngBytesWritten
        ' close handle for current process
        CloseHandle lngProcessHandle
    End Sub
    Public Sub SwapLong(ByRef Value1 As Long, ByRef Value2 As Long)
        Static lngTemp As Long
        lngTemp = Value1
        Value1 = Value2
        Value2 = lngTemp
    End Sub
    Public Sub SwapString(ByRef String1 As String, ByRef String2 As String)
        ' make this procedure point to SwapLong
        ProcedureReplace AddressOf SwapString, AddressOf SwapLong
        ' swap strings using SwapLong
        SwapString String1, String2
    End Sub

    Or just use GetMem4 and PutMem4, although that would be slower I think.


    Edit!
    Or yet another evil hack would be to temporarily switch the memory location of iData's data to point to the sData's memory location. Or do that for another array so it isn't required to be done all the time, just before processing and reset after processing.


    Edit #2
    Oh and the obvious: you could use SendMessage with LB_INITSTORAGE to optimize inserting a lot of items. Also, by temporarily using WM_SETREDRAW to disable drawing and then restoring drawing once done, you can improve the listbox speed without it affecting rest of the application and without making the listbox hidden.
    Last edited by Merri; Oct 21st, 2008 at 03:35 PM.

  14. #14
    PowerPoster Code Doc's Avatar
    Join Date
    Mar 2007
    Location
    Omaha, Nebraska
    Posts
    2,354

    Re: Sorting a ListBox by ItemData?

    Well, note that OP never said where the data in the list box came from. Instead he just showed a table. So, I decided to assume that the data could have been read in from a file somewhere to build the unsorted list box.

    This code solves the OP's problem without using any data arrays or sorting code. Just use an invisible sorted list box to do all the work and then read it back to the visible unsorted list box in correct presentation format:

    Code:
    Private Sub Command1_Click()
    Dim Pointer As Integer
    List2.Clear
    For I = 0 To List1.ListCount - 1
        Pointer = InStr(List1.List(I), "10")
        If Pointer Then List2.AddItem Mid$(List1.List(I), Pointer) & "," & Left$(List1.List(I), Pointer - 1)
    Next
    List1.Clear
    For I = 0 To List2.ListCount - 1
        Pointer = InStr(List2.List(I), ",")
        List1.AddItem Mid$(List2.List(I), Pointer + 1) & Left$(List2.List(I), Pointer - 1)
    Next
    End Sub
    
    Private Sub Form_Load()
    List1.AddItem "Medium Priced 1000"
    List1.AddItem "Most Expensive 10000"
    List1.AddItem "Cheapest Item 100"
    List2.Visible = False
    End Sub
    Doctor Ed

  15. #15
    VB For Fun Edgemeal's Avatar
    Join Date
    Sep 2006
    Location
    WindowFromPoint
    Posts
    4,255

    Re: Sorting a ListBox by ItemData?

    Quote Originally Posted by Code Doc
    Well, note that OP never said where the data in the list box came from. Instead he just showed a table. So, I decided to assume that the data could have been read in from a file somewhere to build the unsorted list box.
    But the the title of this thread is, Sorting a ListBox by ItemData

    I don't see how, List1.AddItem "Medium Priced 1000" is going to solve the OPs problem.

  16. #16
    Former Admin/Moderator MartinLiss's Avatar
    Join Date
    Sep 1999
    Location
    San Jose, CA
    Posts
    33,431

    Re: Sorting a ListBox by ItemData?

    This uses a 3-column ListView with the "Item data" column hidden to sort 10000 items pretty quickly.
    Attached Files Attached Files

  17. #17
    PowerPoster Code Doc's Avatar
    Join Date
    Mar 2007
    Location
    Omaha, Nebraska
    Posts
    2,354

    Re: Sorting a ListBox by ItemData?

    Quote Originally Posted by Edgemeal
    But the the title of this thread is, Sorting a ListBox by ItemData. I don't see how, List1.AddItem "Medium Priced 1000" is going to solve the OPs problem.
    ItemData can be just part of a string. My code works. Please check it again. Simplicity and complexity are not synonymous.

    OP's problem can be solved without using a ListView control and without using even just one array.
    Doctor Ed

  18. #18

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2007
    Posts
    1,072

    Re: Sorting a ListBox by ItemData?

    Wow, I forgot I posted this!

    By default, when setting a listbox's sorted property to true, it sorts them alphabetically.

    The listview control will work perfectly, thanks Marty

    Resolved, feel free to continue posting ideas.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width