Controlling Searches and Comparisons in
.NET
Archive of
Previous Articles

Imports Microsoft.VisualBasic
Imports System
Imports System.Collections

Public Class SearchArray

Public Shared Sub Main()
Dim sStates() As String = {"New York", _
                           "California", _
                           "Michigan", _
                           "Washington"}
Dim sState As String
Dim iResult As Integer

Array.Sort(sStates)
sState = InputBox("Enter state name: ")
iResult = Array.BinarySearch(sStates, sState)
If iResult >= 0 Then
   Console.WriteLine(sState & _
                     " is at position " & _
                     iResult)
Else
   If (Not iResult) = sStates.Length + 1 Then
      Console.WriteLine(sState & " not found.")
   Else
      Console.WriteLine("Nearest match to " & _
          sState & " at position " & not iResult)
   End If
End If
End Sub
End Class
Public Shared Function BinarySearch(ByVal array As Array, _
                           ByVal value As Object _
                          ) As Integer
Public Shared Function BinarySearch(ByVal array As Array, _
                           ByVal value As Object, _
                           ByVal comparer As IComparer _
                          ) As Integer
Imports Microsoft.VisualBasic
Imports System
Imports System.Collections

Public Class SearchArray
Public Shared Sub Main()
Dim cic As New CaseInsensitiveComparer
Dim sStates() As String = {"New York", _
                           "California", _
                           "Michigan", _
                           "Washington"}
Dim sState As String
Dim iResult As Integer

Array.Sort(sStates)
sState = InputBox("Enter state name: ")
iResult = Array.BinarySearch(sStates, sState, cic)
If iResult >= 0 Then
   Console.WriteLine(sState & " is at position " & iResult)
Else
   If (Not iResult) = sStates.Length + 1 Then
      Console.WriteLine(sState & " not found.")
   Else
      Console.WriteLine("Nearest match to " & sState & _
                        " at position " & not iResult)
   End If
End If
End Sub
End Class
Imports Microsoft.VisualBasic
Imports System
Imports System.Collections

Public Class Player
Protected sName As String
Protected sTeam As String
Protected iYear As Integer
Protected sngBA As Single

Public Sub New(name As String, team As String, _
            year As Integer, ba As Single)
sName = name
sTeam = team
iYear = year
sngBA = ba
End Sub

Public ReadOnly Property Name As String
Get
   Return sName
End Get
End Property   

Public ReadOnly Property Team As String
Get
   Return sTeam
End Get
End Property

Public ReadOnly Property Year As Integer
Get
   Return iYear
End Get
End Property

Public ReadOnly Property BA As Single
Get
   Return sngBA
End Get
End Property
End Class

Public Class CompareBA
Implements IComparer

Public Function Compare(x As Object, y As Object) As Integer _
    Implements IComparer.Compare

If TypeOf y Is Player Then
   If x.BA > y.BA Then
      Return 1
   ElseIf x.BA < y.BA Then
      Return -1
   Else
      Return 0
   End If
Else
   If x.BA > y Then
      Return 1
   ElseIf x.BA < y Then
      Return -1
   Else
      Return 0
   End If
End If
End Function
End Class

Public Class PlayerArray

Public Shared Sub Main()
Dim Players(5) As Player
Dim compBA As New CompareBA

Players(0) = New Player("Ty Cobb", "Det", 1910, .385)
Players(1) = New Player("Willie Mays", "S.F.", 1963, .314)
Players(2) = New Player("Cal Ripken", "Balt", 1983, .318)
Players(3) = New Player("Ted Williams", "Bos", 1947, .342)
Players(4) = New Player("Al Kaline", "Det", 1961, .324)
Players(5) = New Player("Ted Williams", "Bos", 1941, .406)
Array.Sort(Players, compBA)        

For Each p As Player In Players
   Console.WriteLine(p.Name & " in " & p.Year & ": " & p.BA)
Next

Dim BAIn As Single
Dim SearchPos As Integer

BAIn = CSng(InputBox("Enter batting average to find: "))
SearchPos = Array.BinarySearch(Players, BAIn, compBA)

If SearchPos >= 0 Then
   Console.WriteLine("BA found at position " & SearchPos & _
                     ": " & Players(SearchPos).Name & _
                     " in " & Players(SearchPos).Year)
Else
   SearchPos = (Not SearchPos)
   If SearchPos = Players.Length + 1 Then
      Console.WriteLine(BAIn & " not found.")
   Else
      Console.WriteLIne("Nearest average to " & BAIn & _
                        " is " & Players(SearchPos).Name & _
                        " in " & Players(SearchPos).Year)
   End If
End If
End Sub

End Class
Class
Member(s)
System.Array  
BinarySearch, Sort
System.Collections.ArrayList
BinarySearch, Sort
System.collections.Hashtable
constructor
System.Collections.Specialized.ListDictionary
constructor
System.Collections.Specialised.NameObjectCollectionBase
constructor
System.Collections.Specialized.NameValueCollection
constructor
System.XML.XPath.XPathExpression
AddSort
System.ComponentModel.EventDescriptorCollection
InternalSort, Sort
System.ComponentModel.PropertyDescriptorCollection
InternalSort, Sort
System.Collections.SortedList  
constructor
System.Windows.Forms.ListView
ListViewItemSorter
System.ComponentModel.EnumConverter
Comparer


Howling Wolf Consulting Services
In Visual Basic 6.0 and earlier versions, string comparisons were controlled by
the
Option Compare statement located at the top of a particular class,
form, or code module. If set to
Text, comparisons were case insensitive. As
a result, code such as

s
tr1 = "string"
str2 = "STRING"

MsgBox str1 = str2

returns True. When the setting is changed to Binary, the string comparison
returns
False. This setting controls all string comparisons and cannot be
changed within a procedure. However, it does not affect the
Item property of
a Visual Basic
Collection object, which always performs a case-
insensitive  comparison. In addition, the
Dictionary class in the Microsoft
Scripting Runtime Library (scrrun.dll) has a
ComnpareMode property that
allows you to determine whether a comparison of dictionary keys is case
sensitive or insensitive.

Visual Basic .NET preserves the
Option Compare statement, which
functions much like it did in previous versions of Visual Basic. However, for
some of the collection-like classes in the .NET Framework, it adds
considerable flexibility by allowing matching and searching to be customized.

In many cases when working with collections and arrays, you may not need to
do anything. By default, comparisons are case sensitive. So if you run the
following code and enter the string “new york” in the input box, a match will
not be found in the array, whereas a match will be found if you enter the string
“New York”:































To support some other comparison or sort method, you have to supply an
object that implements the
IComparer interface as an argument to the
Array object’s BinarySearch method. (A class implementing
IComparer
also can be used to determine the methods for sorting and
comparison for other classes, as the table at the end of this article shows, as
well as for sorting an array.)  The syntax of this version of the
Sort method
then changes from:





to





To make things easy, though, the .NET Framework supplies two classes --
Comparer and CaseInsensitiveComparer -- that implement the
IComparer interface and therefore allow you to change the search and
comparison method automatically. The
Comparer class, in fact, is the default
IComparer implementation if no other is explicitly provided and supports
case-sensitive searches and sorts. Because of these predefined classes,
changing our example to implement a case-insensitive search for a key is very
easy, as the following code shows:






























Regardless of whether we enter “New York” or “new york” (or some other
combination of upper- and lower-case letters) in the input box, the routine will
display the position of the New York element in the array.

But we can also implement our own custom search and sort criteria. The
I
Comparer interface has a single member, Compare. This method takes
two parameters of type
Object, x and y, and returns an Integer indicating
the relationship of
x to y. If x is greater than y (or if x is to follow y), it returns
a positive integer; if x is less than y (or if x is to precede y), it returns a negative
integer; and if the arguments are equal, it returns 0.

For example, let’s imagine that we have an object that represents a baseball
player’s batting average in a particular year. As the following code shows, we
can assign each player’s statistics to an element in the
Players array:





































































































The
CompareBA class is then responsible for sorting the elements in the
order of the batting average, from lowest batting average to highest. We could
easily reverse the sort order by having
CompareBA.Compare return a -1
if x.BA > y.BA and a 1 if y.BA > x.BA.

Although in our examples we have used classes implementing the
IComparer interface only with arrays, implementations of IComparer
can be used to control searching and sorting for a number of classes, including
the following: