Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

ListBox sort not as expected 3

Status
Not open for further replies.

HughLerwill

Programmer
Nov 22, 2004
1,818
GB
The following is giving me a mad morning;

List1.Sorted = True set at design time
Code:
Private Sub Command2_Click()

    List1.AddItem "TEKTIPS / MALTON"
    List1.AddItem "TEK-TIPS / MENWITH HILL"
    List1.AddItem "TEKTIPS / MEXBOROUGH"
    List1.AddItem "TEK-TIPS / NAFFERTON"
    List1.AddItem "TEK-TIPS / AMBERLEY"
    List1.AddItem "TEKTIPS / ARUNDEL"

End Sub

The resulting sort is not as expected, the "-" characters seem to be ignored. Results are as expected if I change the "-" characters for another e.g. ".".

Thanks in advance for any help.
 
>look at ...
Is no better than what I have.
Like I said what I have works very well, in practice I limit search back time, the number of records searched and the number of unique entries found so the actual list is shorter. I just remain curious why it's much faster to retrieve the items in the IDE than an exe in Win7 (64 bit). Did you try the test code I supplied I'm getting 3.6s in the IDE and 16.4s in a pcode exe, going native does'nt seem to help.
I have a feeling that other things exe may be slower than ide under win7 64 bit, I don't have win7 32 bit, tests results from that would be interesting.

>I don't think that helps unless ...(we're probably veering off the thread here!)
You can understand what is apparently being discussed in which I cannot. It seems to suggest that a custom list can be specified in place of the more usual File/ URL lists.
 
I don't have a Win7 machine handy to test, but I do have 2 Vista systems.

One is a slower AMD 2-core 64-bit laptop, the other a faster Intel 4-core 32-bit desktop.

In both cases I saw very close to 1 second difference between tests in the IDE and with a native-code compiled EXE. Then I turned off desktop compisition (Aero) and there is no difference at all.

I didn't expect this since you turn off updates via Visible.

Perhaps I'll have a chance to try a 32-bit Win7 machine in a bit. I do have a tablet machine running that.
 
Yep, same thing here on a 32-bit Win7 tablet.

Just to let you know: I did not change anything in your code. Does your Win7 machine have poor Aero performance? You're seeing a much wider swing in timings than I am on 3 machines.
 
>Does your Win7 machine have poor Aero performance?
No, but Aero is normally disabled, as it was for my timings.
My Vista 32bit machine recently blew up so I have no option to test on that OS just now.
 
Just for fun, I thought I'd tackle this by leveraging some ideas I have previously aired concerning using .NET from VB.

.NET has a number of system collections, some of which are sorted or can be sorted. And the sort can be, in .NET, a custom sort.

Can we somehow use this in VB6? As it turns out, yes. The use of a .NET system collection is the bit previously illustrated (along with stringbuilder)

So, step 1. Add a reference to mscorlib.dll library (which is actually a tlb)

Add a class module (I called mine clsCompare), with the following code:

Code:
[blue]Option Explicit

Implements IComparer

[green]' .Net Compare results
' <0 : x is less than y
' 0  : x equals y
' >0 : x is greater than y[/green]
Public Function IComparer_Compare(ByVal x As Variant, ByVal y As Variant) As Long
    IComparer_Compare = (x < y) [green]' very simple comparison for sake of example - but we could use CompareString previously mentioned if we wanted[/green]
End Function[/blue]

Then in the main project:

Code:
[blue]Option Explicit

Private Sub Command1_Click()
    Dim Sorter As New ArrayList
    Dim myCompare As New clsCompare
    Dim Item as variant
    
    Sorter.Add "TEKTIPS / MALTON"
    Sorter.Add "TEK-TIPS / MENWITH HILL"
    Sorter.Add "TEKTIPS / MEXBOROUGH"
    Sorter.Add "TEK-TIPS / NAFFERTON"
    Sorter.Add "TEK-TIPS / AMBERLEY"
    Sorter.Add "TEKTIPS / ARUNDEL"
    Sorter.Add "TEK-TIPS / MENWITH HILL"
    
    Call Sorter.Sort_2(myCompare) [green]' call the correct overloaded .NET method[/green]
    
    For Each Item In Sorter
        List1.AddItem item
    Next
    
End Sub[/blue]

And there you go. Custom sorting of lists. With almost no code ... (I have no idea how it compares in speed)
 
Thanks strongm that does look like fun, I'll check it out in the morning...
 
dil..ref. timings, ah! if I run the exe 'as Administrator' I get ~3.4s which is very close to the ~3.6s in the ide. The ide has been run 'as administrator' thus far. So I just tried running the ide 'normally' and its timing shot up to 19s.
 
I'm not sure I'd rely on loading the entire .Net elephant just to do a small sort. You could use ADO to do this, probably in less time than adding .Net into the mix would slow program startup.

Code:
Option Explicit

Private Declare Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As Currency) As Long
Private Declare Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As Currency) As Long

Private Sub Command7_Click()
    Dim i&, j&, QPTicks As Currency, QPTicks2 As Currency, QPfreq As Currency
    'List1 is set unsorted at design time
    
    QueryPerformanceFrequency QPfreq
    
    List1.Visible = False
    QueryPerformanceCounter QPTicks
    
    With New ADODB.Recordset
        .CursorLocation = adUseClient
        .Fields.Append "Item", adWChar, 4
        .Open
        !Item.Properties("Optimize") = True
            
        For i = 1 To 1000
            .AddNew Array(0), Array(CStr(i))
        Next
        
        .Sort = "Item ASC"
        For j = 1 To 100
            List1.Clear
            .MoveFirst
            Do Until .EOF
                List1.AddItem !Item.Value
                .MoveNext
            Loop
        Next
        .Close
    End With
    
    QueryPerformanceCounter QPTicks2
    List1.Visible = True
    
    MsgBox j - 1 & "*" & List1.ListCount & " Items in " & (QPTicks2 - QPTicks) / QPfreq & " seconds"
End Sub
 
Er .. ADO has the same sorting 'limitation' that we are trying to work around. I'd already had a look at this.
 
Easy fix there too, e.g.:

Code:
Dim Bytes() As Byte
...
Code:
.Fields.Append "Item", adLongVarBinary, 100 '2 x Max, since we're stuffing in Unicode.
...
Code:
Bytes = CStr(i)
.AddNew Array(0), Array(Bytes)
...
Code:
List1.AddItem !Item.Value 'VB will convert the data back to String.
 
Hugh has previously mentioned that binary sorting is still less than ideal, since he wants case insensitivity ...
 
dil.. thanks for the ADO example which I got running (pre Easy fix only so far). Notwithstanding issues with the sort produced it seems way slow eg. cut and pasted it is taking about 43s here.
I don't use ADO routinely and used a reference to ADO 6.1.

I think I'm happy enough with the speed I'm getting from the QuickSorted string array (Method 4), however, I'd still like to know why I'm getting slower speeds when the exe (or ide) are not being run 'as administrator' under Win7 64 bit.
 
>seems way slow
dil..Sorry, I missed the second loop 'For j = 1 To 100' you put in there to extend the time taken.
Using the same dataset as in the other timings I'm now getting ~0.5s.

strongm - I thought I'd answered you earlier re your NET solution however it seems it did not get submitted.
Anyway thanks it works fine, it times in at ~0.74s on the reference dataset.
I'm using IComparer_Compare = StrComp(UCase$(x), UCase$(y), vbBinaryCompare) = -1 in the Class which is giving the desired sort behaviour.


 
>loading the entire .Net elephant

Ah, but it doesn't. mscorelib only really needs the CLR engine loaded which comes in at under 6Mb (mscoree 290Kb plus mscorwrks 5.6Mb ). Admittedly not as lightweight as the ADO dll, but somewhat smaller than you might be thinking. And since it is impilmented as a native image (i.e. precompiled) it avoids the necessity of the JIT.

And, when using CompareString in the Compare method, it seems to be about twice as fast as the ADO solution, at least on my XP machine (IDE and compiled)
 
> Ah, but it doesn't. mscorelib only really needs the CLR engine loaded

Good to know. Sounds feasible then, especially if the user's machine isn't Vista or later with .Net broken (can't be repaired in many cases, requires reformat/reinstall of Windows).


Yes, the ADO solution isn't ideal but besides that and ListBox sorting there are darned few off the shelf sorts readily available in VB6. Case insensitivity can be achieved at additional penalty by using an indexed and sorted UCase$()'ed value and a second carried-along original value - but then the performance penalties really begin to mount.
 
If you have a sort that provides the ordering you desire and you can trust it not to have flaws, I guess you have your solution.
 
Yes thanks to you both for your help over the past few days.
And I have CompareString working now too.
 
Why would you want to rely on CompareString() calls at all? It has a lot of overhead because it works hard to do pretty much what you don't want.

Its injection into the discussion made it really unclear what you are after. I had thought you wanted something like a binary compare after converting both items to uppercase. Now I don't know about that.

Are you hoping for something "extra" from these calls or just reveling in excessive complexity? Are you trying to deal with international issues?

suggests this is something to be used cautiously.
 
dil.. thanks. I just said I had it working, I don't intend on relying on it mainly because so far I'm finding it a tad slower than the StrComp call which is achieving what I want. I just wanted to investigate that avenue.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top