Results 1 to 11 of 11

Thread: Sorting Listview by comparing values

  1. #1

    Thread Starter
    Lively Member
    Join Date
    Jan 2011
    Location
    Albany, OR
    Posts
    76

    Sorting Listview by comparing values

    I am having a little trouble figuring out a method of doing this. Basically, I have a listview that contains a bunch of poker hands. I have written a function to convert a text string into a hand. (Example: AS-2S-3S-4S-5S results in a straight flush.) I have also wrote a function to compare two hands to see which one wins. Now I need to cycle through my listview and sort the hands using my compare function. Since it is hard to reorder a listview, I thought maybe would be better to add a new column with a rank. The hand with 1 in the rank column would be the highest hand.

    Right now, I'm just trying to wrap my head around the logic. Any help would be appreciated.
    Chad L. Hutson
    Owner, CPU Vet
    Veterans In The Computer Repair Business!
    http://www.cpuvet.com

  2. #2
    PowerPoster
    Join Date
    Feb 2012
    Location
    West Virginia
    Posts
    14,205

    Re: Sorting Listview by comparing values

    Yep adding a rank and then sort by rank, should be simple
    http://www.vbforums.com/showthread.p...s-numbers-text

  3. #3

    Thread Starter
    Lively Member
    Join Date
    Jan 2011
    Location
    Albany, OR
    Posts
    76

    Re: Sorting Listview by comparing values

    Thanks for the response, but it's not quite what I'm looking for. That project basically shows how to sort a listview by clicking on a column. I could use that to sort the rank column numerically, but what I need is to assign a rank to each hand first. I hope that makes sense.
    Chad L. Hutson
    Owner, CPU Vet
    Veterans In The Computer Repair Business!
    http://www.cpuvet.com

  4. #4
    PowerPoster
    Join Date
    Feb 2012
    Location
    West Virginia
    Posts
    14,205

    Re: Sorting Listview by comparing values

    So what are you asking?

    I would imagine that there are lots of samples online related to poker hands.

    Why are you using a listview at all? I would probably just use arrays

  5. #5

    Thread Starter
    Lively Member
    Join Date
    Jan 2011
    Location
    Albany, OR
    Posts
    76

    Re: Sorting Listview by comparing values

    The listview is displaying the results. Basically, I will have 50-300 people submitting a poker hand. The listview displays each poker hand and who it belongs to. Once everyone submits their hands, I need to find out who has the highest and lowest hands. I suppose it would be a little easier to just get the high and low hands, but I would just like to sort the whole list. The listview looks like this:

    Name Cards Hand Rank?
    Chad AS-2S-3C-4D-5H Straight ?
    John 2S-3S-4S-5S-6S Straight Flush ?
    etc.

    I wrote a function that will take 2 hands and find out which one wins. Now I just need to sort the list. I only added the Rank column for sorting purposes. It could go away if it is not needed, but I figured it would be easier to fill in a rank than to sort the listview. Once the Rank column is filled, it could easily be sorted by that column.
    Chad L. Hutson
    Owner, CPU Vet
    Veterans In The Computer Repair Business!
    http://www.cpuvet.com

  6. #6
    Frenzied Member
    Join Date
    Apr 2012
    Posts
    1,254

    Re: Sorting Listview by comparing values

    If you are already using a function that compares two hands, then you already have the basis of a sorting mechanism in place, surely? Ranking 50-300 hands is simply a matter of bubble-sorting your 300 hands using your existing function to move items toward the top as you compare them. Lots of bubble sort examples here...
    If you don't know where you're going, any road will take you there...

    My VB6 love-children: Vee-Hive and Vee-Launcher

  7. #7
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,708

    Re: Sorting Listview by comparing values

    The standard API sort would work well in this situation if I understand it correctly, since it sorts by comparing 2 items. The only particularly burdensome part is you need to set the lParam to identify items.

    But if you did that... you would send LVM_SORTITEMS, with the address of the compare proc. The compare proc compares 2 items and sorts based on the results. So you could look up each item from the lparam, then pass their hands to your function that determines which wins. So it doesn't sort by the value in the column (although you could), it takes the info from the columns - the two player hands - and sorts based on which one you say wins.

    Using an API sort has the additional benefit, I believe, of being much faster than non-API sort methods, which may be significant if you're frequently sorting 300 items. (and if it's not faster, it would be if it was an pure API listview, so shh).

    Here's basically what you would need. I haven't ran this code, so it might have errors, and cutting out just the definitions needed from my def files which have every listview api def ever would take a good 20-30minutes... I'll leave at least that part to you. Everything is the standard ANSI api definition (lvitem with psztext as string, etc.. no unicode).

    Code:
    Public Sub SortListView()
    
    Call ListView_SortItems(ListView1.hWnd, 0, AddressOf ListViewSortProc)
    End Sub
    Public Function SetLVItemlParam(hWnd As Long, iItem As Long, lParam As Long) As Long
    
    'you'd have to call this function each time you added an item with a unique value
    'for lparam. the index would be fine.
    Dim lvi As LVITEM
    
    lvi.mask = LVIF_PARAM
    lvi.iItem = iItem
    lvi.lParam = lParam
    
    SetLVItemlParam = SendMessage(hWnd, LVM_SETITEM, 0, lvi)
    
    End Function
    
    Public Function ListView_SortItems(hWndLV As Long, pfnCompare As Long, lParamSort As Long) As Boolean
      ListView_SortItems = SendMessage(hWndLV, LVM_SORTITEMS, ByVal lParamSort, ByVal pfnCompare)
    End Function
    
    Public Function ListViewSortProc(ByVal lParam1 As Long, _
                                 ByVal lParam2 As Long, _
                                 ByVal lParamSort As Long) As Long
         
    
       Dim sHand1 As String
       Dim sHand2 As String
       Dim lResult As Long
    sHand1 = GetLVHand(lParam1)
    sHand2 = GetLVHand(lParam2)
    
    ListViewSortProc = CompareHands(sHand1, sHand2)
    'your CompareHands procedure would have to return 0, 1, or 2
    'where 1 means the hands are the same. 
    'Alternatively, If you did have a rank column, you could just
    'get those values and compare them directly like a standard sort
    'lHand1,2 = GetHandRank(...just get a different subitem than GetLVHand)
    'If lHand1 <, =, > then return 0,1,2
    
    End Function
    
    Public Function GetLVHand(lParam As Long) As String
      
    Dim hIndex As Long
    Dim r As Long
    Dim lvf As LVFINDINFO
    Dim lvi As LVITEM
    lvf.Flags = LVFI_PARAM
    lvf.lParam = lParam
    hIndex = SendMessage(hWnd, LVM_FINDITEM, -1, lvf)
      
    lvi.mask = LVIF_TEXT
    lvi.iSubItem = 1 'or whichever subitem contains the players hands
    lvi.pszText = Space$(32)
    lvi.cchTextMax = Len(lvi.pszText)
    
    r = SendMessage(hWnd, LVM_GETITEMTEXT, hIndex, lvi)
    If r > 0 Then
       GetLVHand = Left$(lvi.pszText, r)
    End If
      
    End Function
    Last edited by fafalone; May 28th, 2014 at 02:15 PM.

  8. #8

    Thread Starter
    Lively Member
    Join Date
    Jan 2011
    Location
    Albany, OR
    Posts
    76

    Re: Sorting Listview by comparing values

    That last code is a little above my head. I don't really see what is going on there.
    I have been playing with the Collection method that I mentioned above, but I can't get it quite right. It seems to be close. The order is just a bit off. Maybe someone can see what is wrong with it. Keep in mind, I am not a real programmer. I just do this as a hobby occasionally.

    Code:
    Public Sub RankHands(lvw As ListView)
        Dim colHands As New Collection
        Dim LI As ListItem
        Dim Hand1 As Hand
        Dim Hand2 As Hand
        Dim iWinner As Integer
        Dim TempIndex As Integer
        Dim x As Integer
        Dim y As Integer
      
        
        'Add first list item to collection
        colHands.Add lvw.ListItems(1)
        
        'Insert remaining listitems into collection
        For x = 2 To lvw.ListItems.Count
            Set LI = lvw.ListItems(x)
            Hand1 = StringToHand(LI.SubItems(1))
            
            For y = 1 To colHands.Count
                Hand2 = StringToHand(colHands(y).SubItems(1))
                iWinner = CompareHands(Hand1, Hand2)
    
                Select Case iWinner
                    Case 0
                        'Tie
                        If y = colHands.Count Then colHands.Add LI, LI, , y
                    Case 1
                        'Hand1 wins
                        colHands.Add LI, LI, y
                        If y < colHands.Count Then Exit For
                    Case 2
                        'Hand2 wins
                        If y = colHands.Count Then colHands.Add LI, LI, , y
                    Case Else
                        MsgBox "Error"
                End Select
            Next y
        Next x
        
        
        'Write collection back to listview
        For y = 1 To lvw.ListItems.Count
            lvw.ListItems(y).SubItems(3) = colHands(y).index
        Next y
    
        
    End Sub
    Chad L. Hutson
    Owner, CPU Vet
    Veterans In The Computer Repair Business!
    http://www.cpuvet.com

  9. #9
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,708

    Re: Sorting Listview by comparing values

    I can't follow your code either so...
    My code would work like:

    1) When you add an item to the list, you also call SetLVItemlParam(listview.hwnd, item number, item number again since that is unique)
    2) Call the SortListView function

    And the only changes youd make,
    -In ListviewSortProc, just convert the string that's returned from subitem 1 (A-Q-9 whatever) to your hand object
    -Your CompareHands should return 1 as a tie, and 0 or 2 for a winner

    It was magic to me at first too, fortunately you don't need to worry about how exactly it works, just have to change a couple details. It really is the best way to do this; trying to do it another way is going to be just as complicated. Sorting isn't easy to get your head around if you're not using it frequently.

  10. #10

    Thread Starter
    Lively Member
    Join Date
    Jan 2011
    Location
    Albany, OR
    Posts
    76

    Re: Sorting Listview by comparing values

    Thanks for the help, but I think I'm going to give up on this. I can sort it by hand type (Straight, Flush, etc.) since each hand type is just an integer anyway. Then I will just have to manually compare hands of the same type.
    Chad L. Hutson
    Owner, CPU Vet
    Veterans In The Computer Repair Business!
    http://www.cpuvet.com

  11. #11
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,253

    Re: Sorting Listview by comparing values

    Quote Originally Posted by littlewing1977 View Post
    Thanks for the help, but I think I'm going to give up on this. I can sort it by hand type (Straight, Flush, etc.) since each hand type is just an integer anyway. Then I will just have to manually compare hands of the same type.
    Well your *principle* sorting approach may be right (I havent tested what you posted in #8) -
    but the errors creep in IMO, because you don't store "hard values" in your collection,
    but the reference-values to the ListItem-Objects themselves.

    I'd deal with your Hand-Strings directly instead (avoiding Object-Refs).

    As I see it - what you attempt is an enumeration of "Hands" which exist in a ListView -
    entering them whilst doing so into a collection - then refilling the listview from the
    (now sorted) collection, after the enumeration-loop is through.

    Below is an example which demonstrates that with simplified strings (and not
    using a ListView, but a ListBox) - but that's what should be easy to adapt.

    Code:
    Option Explicit
    
    Private Sub Form_Load() 'Demo-Data
      List1.AddItem "456"
      List1.AddItem "xyz"
      List1.AddItem "abc"
      List1.AddItem "123"
    End Sub
     
    Private Sub Form_Click()
    Dim i As Long, Col As New Collection
    
      For i = 0 To List1.ListCount - 1 'sorted adding to the Col
        AddSortedTo Col, List1.List(i)
      Next i
      
      List1.Clear 'clear the List-Content
      
      For i = 1 To Col.Count 're-add the List-Content
        List1.AddItem Col(i)
      Next i
    End Sub
    
    Private Sub AddSortedTo(Col As Collection, ByVal Item As String)
    Dim i As Long
    
      'exit early, as soon as the the current ColItem becomes > than our new one (the Item-Parameter of this Sub)
      For i = 1 To Col.Count
        If CompareHandStrings(Col(i), Item) = 1 Then Exit For
      Next
      
      If i > Col.Count Then Col.Add Item Else Col.Add Item, , i
    End Sub
    
    Private Function CompareHandStrings(ByVal strH1 As String, ByVal strH2 As String) As Long
      CompareHandStrings = StrComp(strH1, strH2)
    End Function
    The above function: CompareHandStrings

    needs to be adjusted by you appropriately - currently it hands out
    the result of the StrComp-function - just mimic that behaviour in your
    Hand-comparison:
    -1 when smaller
    0 when equal
    1 when larger

    It's just a principle-demo I was trying to keep as understandable as possible.

    Olaf

Tags for this Thread

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