'-------------------------------------------------
' Searching, Sorting, and Multitasking Comparisons
'
' Written By Jeffrey B. Firestone
' Jeffrey B. Firestone Company
' jfirestone@jbfc.com
'
' May 29, 2004
'
' You may redistribute this control in binary and modified binary form as you please. You may
' use this control in commercial applications without need for external credit royalty free.
'
' However, you are restricted from releasing the source code in any modified fashion
' whatsoever.
'
' I MAKE NO PROMISES OR WARRANTIES ON THIS CODE/CONTROL. IF ANY DAMAGE OR PROBLEMS HAPPEN FROM ITS USE
' THEN YOU ARE RESPONSIBLE.
Option Strict On
Imports System.Windows.Forms
Imports VB = Microsoft.VisualBasic
Imports System.Random
Imports System.Data
Public Class HashtableCollection
Implements IDisposable
Private m_frmMain As frmMain
Private m_IsInitialized As Boolean
Private m_IsRunning As Boolean
Private m_Hashtable As System.Collections.Hashtable
Private m_iColumnNumber As Integer
Private m_iRowNumber As Integer
#Region "Properties"
Public ReadOnly Property ClassDescription() As String
Get
ClassDescription = "Hashtable Collection"
End Get
End Property
Public Property frmMain() As Form
Get
frmMain = m_frmMain
End Get
Set(ByVal Value As Form)
m_frmMain = CType(Value, frmMain)
End Set
End Property
Public Property IsInitialized() As Boolean
Get
IsInitialized = m_IsInitialized
End Get
Set(ByVal Value As Boolean)
m_IsInitialized = Value
End Set
End Property
Public Property IsRunning() As Boolean
Get
IsRunning = m_IsRunning
End Get
Set(ByVal Value As Boolean)
m_IsRunning = Value
End Set
End Property
Public ReadOnly Property DataSize() As Integer
Get
If Not (m_Hashtable Is Nothing) Then
DataSize = m_Hashtable.Count
End If
End Get
End Property
#End Region
#Region "Publics"
Public Function RunProc(ByVal iColumnNumber As Integer, ByVal iRowNumber As Integer) As String
Dim strResults As String = ""
IsRunning = True
m_iColumnNumber = iColumnNumber
m_iRowNumber = iRowNumber
Select Case iColumnNumber
Case 0 : ShowData()
Case 1 : strResults = Create()
Case 2 : strResults = DatasetScan()
Case 3 : strResults = Find_1_Key_Field()
Case 4 : strResults = Find_All_NonKey_Values()
Case 5 : strResults = Find_n_Fields()
Case 6 : strResults = Sort()
End Select
IsRunning = False
Return strResults
End Function
Public Function Create() As String
Dim t As Double = VB.Timer()
#If 1 Then
' The HashTable's internal management routines are optimized for a prime number
' of elements. So, where possible, create a new HashTable with a number of elements
' equaling 11, 53, 101, 503, 1009, 5003, 10007, etc.
Dim lDataSize As Integer = GetNextPrime(m_frmMain.Data_Size)
#Else
' This is a bit slower
Dim lDataSize As Integer = m_frmMain.Data_Size
#End If
m_Hashtable = Nothing
m_Hashtable = New System.Collections.Hashtable(lDataSize)
For lCount As Integer = 0 To m_frmMain.Data_Size
Dim oTestData As TestData.TestDataStructure = m_frmMain.TestData.arTestData(lCount)
m_Hashtable.Add(oTestData.sUnique, oTestData)
Next
m_IsInitialized = True
t = VB.Timer() - t
Return CStr(IIf(m_frmMain.fCancel, ">", "")) & Format(t, "0.00")
End Function
Public Function DatasetScan() As String
Dim lUnique As Integer
Dim sUnique As String
Dim lNonUnique As Integer
Dim sNonUnique As String
If Not m_IsInitialized Or DataSize <> m_frmMain.Data_Size Then Create()
Dim t As Double = VB.Timer()
Dim lScanRepeat As Integer = m_frmMain.Scan_Repeat
For lScanCount As Integer = 0 To lScanRepeat
If m_frmMain.rbDoEvents.Checked Then Application.DoEvents()
If m_frmMain.fCancel Then Exit For
If lScanCount Mod Math.Max(lScanRepeat \ 10,1) = 0 Then m_frmMain.UpdateProgress(m_iRowNumber, m_iColumnNumber, (lScanCount * 100) \ lScanRepeat)
Dim e As System.Collections.IEnumerator = m_Hashtable.GetEnumerator()
While e.MoveNext()
With DirectCast(e.Current.Value, TestData.TestDataStructure)
lUnique = .lUnique
sUnique = .sUnique
lNonUnique = .lNonUnique
sNonUnique = .sNonUnique
End With
End While
e = Nothing
Next
t = VB.Timer() - t
Return CStr(IIf(m_frmMain.fCancel, ">", "")) & Format(t, "0.00")
End Function
Public Function Find_1_Key_Field() As String
Dim s As String
Dim sFind As String
Dim lFind As Integer
Dim rndGen As New System.Random
If Not m_IsInitialized Or DataSize <> m_frmMain.Data_Size Then Create()
Dim t As Double = VB.Timer()
Dim lDataSize As Integer = m_frmMain.Data_Size
Dim lFindRepeat As Integer = m_frmMain.Find_Repeat
For lCount As Integer = 0 To lFindRepeat
If m_frmMain.rbDoEvents.Checked Then Application.DoEvents()
If m_frmMain.fCancel Then Exit For
If lCount Mod Math.Max((lFindRepeat \ 10), 1) = 0 Then m_frmMain.UpdateProgress(m_iRowNumber, m_iColumnNumber, (lCount * 100) \ lFindRepeat)
sFind = "Str" & CInt(rndGen.Next(lDataSize))
Dim oData As TestData.TestDataStructure = DirectCast(m_Hashtable.Item(sFind), TestData.TestDataStructure)
s = oData.sUnique
Next
t = VB.Timer() - t
Return CStr(IIf(m_frmMain.fCancel, ">", "")) & Format(t, "0.00")
End Function
Public Function Find_All_NonKey_Values() As String
Dim lFound As Integer
Dim rndGen As New System.Random
If Not m_IsInitialized Or DataSize <> m_frmMain.Data_Size Then Create()
Dim t As Double = VB.Timer()
Dim lDataSize As Integer = m_frmMain.Data_Size
Dim lFindRepeat As Integer = m_frmMain.Find_Repeat
For lCount As Integer = 0 To lFindRepeat
If m_frmMain.rbDoEvents.Checked Then Application.DoEvents()
If m_frmMain.fCancel Then Exit For
If lCount Mod Math.Max((lFindRepeat \ 10), 1) = 0 Then m_frmMain.UpdateProgress(m_iRowNumber, m_iColumnNumber, (lCount * 100) \ lFindRepeat)
Dim lFind As Integer = CInt(rndGen.Next(CInt(lDataSize / 10)))
Dim e As System.Collections.IEnumerator = m_Hashtable.GetEnumerator()
While e.MoveNext()
With DirectCast(e.Current.Value, TestData.TestDataStructure)
If .lNonUnique = lFind Then
lFound = .lNonUnique
End If
End With
End While
Next
t = VB.Timer() - t
Return CStr(IIf(m_frmMain.fCancel, ">", "")) & Format(t, "0.00")
End Function
Public Function Find_n_Fields() As String
Dim s As String
Dim sFind As String
Dim lHits As Integer = 0
Dim rndGen As New System.Random
If Not m_IsInitialized Or DataSize <> m_frmMain.Data_Size Then Create()
Dim t As Double = VB.Timer()
Dim lDataSize As Integer = m_frmMain.Data_Size
Dim lFindRepeat As Integer = m_frmMain.Find_Repeat
For lCount As Integer = 0 To lFindRepeat
If m_frmMain.rbDoEvents.Checked Then Application.DoEvents()
If m_frmMain.fCancel Then Exit For
If lCount Mod Math.Max((lFindRepeat \ 10), 1) = 0 Then m_frmMain.UpdateProgress(m_iRowNumber, m_iColumnNumber, (lCount * 100) \ lFindRepeat)
sFind = "Str" & CInt(rndGen.Next(lDataSize))
Dim oData As TestData.TestDataStructure = DirectCast(m_Hashtable.Item(sFind), TestData.TestDataStructure)
With oData
If StrComp(.sUnique, sFind, CompareMethod.Binary) = 0 AndAlso StrComp(.sNonUnique, "Second", CompareMethod.Binary) = 0 Then
lHits = lHits + 1
s = oData.sUnique
End If
End With
Next
t = VB.Timer() - t
s = CStr(IIf(m_frmMain.fCancel, ">", "")) & Format(t, "0.00") & " (" & lHits & " recs)"
Return s
End Function
Public Function Sort() As String
If Not m_IsInitialized Or DataSize <> m_frmMain.Data_Size Then Create()
Dim t As Double = VB.Timer()
Dim aData(m_frmMain.Data_Size) As TestData.TestDataStructure
m_Hashtable.Values.CopyTo(aData, 0)
Dim oTestDataIComparer As New TestData.lNonUnique_IComparer
System.Array.Sort(aData, oTestDataIComparer)
oTestDataIComparer = Nothing
Dim lUnique As Integer
Dim sUnique As String
Dim lNonUnique As Integer
Dim sNonUnique As String
For l As Integer = 0 To m_Hashtable.Count - 1
Dim oData As TestData.TestDataStructure = DirectCast(m_Hashtable.Item(aData(l).sUnique), TestData.TestDataStructure)
With oData
lUnique = .lUnique
sUnique = .sUnique
lNonUnique = .lNonUnique
sNonUnique = .sNonUnique
End With
Next
t = VB.Timer() - t
Return CStr(IIf(m_frmMain.fCancel, ">", "")) & Format(t, "0.00")
End Function
Public Function ShowData() As Boolean
Dim frm As ShowData = New ShowData
With frm.dt.Columns
.Add(New DataColumn("lUnique", GetType(Integer)))
.Add(New DataColumn("sUnique", GetType(String)))
.Add(New DataColumn("lNonUnique", GetType(Integer)))
.Add(New DataColumn("sNonUnique", GetType(String)))
End With
If Not (m_Hashtable Is Nothing) Then
Dim e As System.Collections.IEnumerator = m_Hashtable.GetEnumerator()
While e.MoveNext()
With DirectCast(e.Current.Value, TestData.TestDataStructure)
Dim dr As DataRow
dr = frm.dt.NewRow
dr.BeginEdit()
dr.Item("lUnique") = .lUnique
dr.Item("sUnique") = .sUnique
dr.Item("lNonUnique") = .lNonUnique
dr.Item("sNonUnique") = .sNonUnique
dr.EndEdit()
frm.dt.Rows.Add(dr)
End With
End While
End If
With frm
.dg.DataSource = .dt
.Show()
frm.Text = ClassDescription
End With
End Function
#End Region
#Region "Privates"
' Returns a prime number that is equal or greater than the given number
Private Function GetNextPrime(ByVal baseNumber As Integer) As Integer
Dim n As Integer = baseNumber
' Arguments : baseNumber - The starting number from which to compute the current or next prime
' Returns : Current Number (if prime) or Next larger prime number
If n Mod 2 = 0 Then n += 1
Do Until IsNumberPrime(n) Or (n = n.MaxValue)
n += 2
Loop
Return n
End Function
' Determines if a number is a prime number
Private Function IsNumberPrime(ByVal numberToCheck As Integer) As Boolean
' Arguments : numberToCheck - The number to check
' Returns : True if the number is prime
' False if the number is not prime
Dim counter As Integer
Dim test As Integer
Dim limit As Integer
Dim isPrime As Boolean
' Convert the number to a positive value
test = System.Math.Abs(numberToCheck)
Select Case test
Case 0, 1
isPrime = False
Case 2
isPrime = True
Case Else
If test Mod 2 = 0 Then
' Even numbers are not prime.
isPrime = False
Else
' Odd numbers need to be tested.
' Test if an odd number divides into the value
' without a remainder. Test to square root of value.
isPrime = True
limit = CType((System.Math.Sqrt(test)) + 1, Integer)
For counter = 3 To limit Step 2
If test Mod counter = 0 Then
' Number is not prime
isPrime = False
Exit For
End If
Next counter
End If
End Select
Return isPrime
End Function
#End Region
#Region "Dispose"
Public Sub Dispose() Implements System.IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If disposing Then
' Free dependent objects
m_Hashtable = Nothing
End If
' Free un-managed resources
' No managed resource here.
' Must be thread-safe here.
End Sub
Protected Overrides Sub Finalize()
Dispose(False)
End Sub
#End Region
End Class