Previous section   Next section

9.6 .NET Collection Types: Beyond Array

The Array class is the simplest of the collection types provided with the .NET Framework. But the Framework provides a number of more powerful collection classes. The remaining pages of this chapter describe some of these very useful collection classes: ArrayList, Collection, Queue, and Stack.

9.6.1 Array Lists

Imagine that your program asks the user for input or gathers input from a web site. As it finds objects (strings, books, values, etc.), you would like to add them to an array, but you have no idea how many objects you'll collect in any given session.

It is difficult to use an array for such a purpose because you must declare the size of an Array object at compile time. If you try to add more objects than you've allocated memory for, the Array class will throw an exception. If you do not know in advance how many objects your array will be required to hold, you run the risk of declaring either too small an array (and running out of room) or too large an array (and wasting memory).

The .NET Framework provides a class designed for just this situation. The ArrayList class is an array whose size is dynamically increased as required. The ArrayList class provides many useful methods and properties. A few of the most important are shown in Table 9-4.

Table 9-4. ArrayList members

Method or property

Purpose

Add( )

Method to add an object to the ArrayList

Capacity

Property containing the number of elements the array can currently hold

Clear( )

Method that removes all elements from the ArrayList

Count

Property to return the number of elements currently in the array

GetEnumerator( )

Method that returns an enumerator to iterate an ArrayList

Insert( )

Method that inserts an element into ArrayList

Item( )

Method that gets or sets the element at the specified index; this is the indexer for the ArrayList class

RemoveAt( )

Method that removes the element at the specified index

Reverse( )

Method that reverses the order of elements in the ArrayList

Sort( )

Method that alphabetically sorts the ArrayList

ToArray( )

Method that copies the elements of the ArrayList to a new array

When you create an ArrayList, you do not define how many objects it will contain. You add to the ArrayList using the Add( ) method, and the list takes care of its own internal bookkeeping, as illustrated in Example 9-13.

Example 9-13. Using an ArrayList
Option Strict On
Imports System

Namespace ArrayListDemo
    'a class to hold in the array list
    Public Class Employee
        Private myEmpID As Integer

        Public Sub New(ByVal empID As Integer)
            Me.myEmpID = empID
        End Sub 'New

        Public Overrides Function ToString( ) As String
            Return myEmpID.ToString( )
        End Function 'ToString

        Public Property EmpID( ) As Integer
            Get
                Return myEmpID
            End Get
            Set(ByVal Value As Integer)
                myEmpID = Value
            End Set
        End Property
    End Class 'Employee

    Class Tester

        Public Sub Run( )
            Dim empArray As New ArrayList( )
            Dim intArray As New ArrayList( )

            'populate the arraylists
            Dim i As Integer
            For i = 0 To 4
                empArray.Add(New Employee(i + 100))
                intArray.Add((i * 5))
            Next i

            'print each member of the array
            For Each i In intArray
                Console.Write("{0} ", i.ToString( ))
            Next i

            Console.WriteLine(ControlChars.Lf)

            'print each employee
            Dim e As Employee
            For Each e In empArray
                Console.Write("{0} ", e.ToString( ))
            Next e

            Console.WriteLine(ControlChars.Lf)
            Console.WriteLine("empArray.Capacity: {0}", empArray.Capacity)
        End Sub 'Run


        Shared Sub Main( )
            Dim t As New Tester( )
            t.Run( )
        End Sub 'Main
    End Class 'Tester

End Namespace 'ArrayListDemo

Output:
0 5 10 15 20
100 101 102 103 104
empArray.Capacity: 16

Suppose you're defining two ArrayList objects, empArray to hold Employee objects, and intArray to hold integers:

Dim empArray As New ArrayList( )
Dim intArray As New ArrayList( )

Each ArrayList object has a property, Capacity, which is the number of elements the ArrayList is capable of storing.

The default capacity for the ArrayList class is 16. You are free to set a different starting capacity for your ArrayList, but typically there is no need for you ever to do so.

You add elements to the ArrayList with the Add( ) method:

empArray.Add(New Employee(i + 100))
intArray.Add((i * 5))

When you add the 17th element, the capacity is automatically doubled to 32. If you change the For loop to:

For i = 0 To 17

the output looks like this:

0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
empArray.Capacity: 32

Similarly, if you added a 33rd element, the capacity would be doubled to 64. The 65th element increases the capacity to 128, the 129th element increases it to 256, and so forth.

9.6.2 The Collection Class

Visual Basic .NET offers a generic collection class named, aptly, Collection. In many ways, the Collection object serves as an object-oriented alternative to Array, much as ArrayList does.

These two constructs (ArrayList and Collection) are very similar. Both offer Add( ) and Remove( ) methods as well as an Item property. The Collection class, however, overloads the Item property to take a string as a key into the collection. This allows the Collection class to act as a dictionary, associating keys with values. You can also use the Item property to access members of the collection by index value; however, the Collection uses a one-based index (i.e., the first element is index 1 rather than 0).

Example 9-14 illustrates the use of a Visual Basic .NET Collection object.

Example 9-14. Using a Collection object
Option Strict On
Imports System

Namespace CollectionDemo
    'a class to hold in the array list
    Public Class Employee
        Private myEmpID As Integer

        Public Sub New(ByVal empID As Integer)
            Me.myEmpID = empID
        End Sub 'New

        Public Overrides Function ToString( ) As String
            Return myEmpID.ToString( )
        End Function 'ToString

        Public Property EmpID( ) As Integer
            Get
                Return myEmpID
            End Get
            Set(ByVal Value As Integer)
                myEmpID = Value
            End Set
        End Property
    End Class 'Employee

    Class Tester

        Public Sub Run( )
            Dim intCollection As New Collection( )
            Dim empCollection As New Collection( )
            Dim empCollection2 As New Collection( )

            'populate the Collections
            Dim i As Integer
            For i = 0 To 4
                empCollection.Add(New Employee(i + 100))
                intCollection.Add((i * 5))
            Next i

            'add key/value pairs
            empCollection2.Add(New Employee(1789), "George Washington")
            empCollection2.Add(New Employee(1797), "John Adams")
            empCollection2.Add(New Employee(1801), "Thomas Jefferson")


            'print each member of the array
            For Each i In intCollection
                Console.Write("{0} ", i.ToString( ))
            Next i

            Console.WriteLine( )
            Console.WriteLine("Employee collection...")
            Dim e As Employee
            For Each e In empCollection
                Console.Write("{0} ", e.ToString( ))
            Next e

            Console.WriteLine( )
            Console.WriteLine("Employee collection 2...")
            For Each e In empCollection2
                Console.Write("{0} ", e.ToString( ))
            Next e

            Console.WriteLine( )

            'retrieve an Employee by key 
            Dim emp As Employee
            emp = empCollection2.Item("John Adams")
            Console.WriteLine( _
              "Key John Adams retrieved empID {0}", emp.ToString( ))

            'note that indexing is 1-based (rather than zero based)
            emp = empCollection2.Item(1)
            Console.WriteLine( _
              "Index(1) retrieved empID {0}", emp.ToString( ))

        End Sub 'Run


        Shared Sub Main( )
            Dim t As New Tester( )
            t.Run( )
        End Sub 'Main
    End Class 'Tester
End Namespace 'CollectionDemo

Output:
0 5 10 15 20
Employee collection...
100 101 102 103 104
Employee collection 2...
1789 1797 1801
Key John Adams retrieved empID 1797
Index(1) retrieved empID 1789

Example 9-14 creates three Collection objects (intCollection, empCollection, and empCollection2):

Dim intCollection As New Collection( )
Dim empCollection As New Collection( )
Dim empCollection2 As New Collection( )

The first two objects are populated in For loops, just as the ArrayList was created in Example 9-13:

Dim i As Integer
For i = 0 To 4
    empCollection.Add(New Employee(i + 100))
    intCollection.Add((i * 5))
Next i

The third Collection object, empCollection2, is populated using key values. Each new Employee is associated with a string, representing the name of the Employee:

empCollection2.Add(New Employee(1789), "George Washington")
empCollection2.Add(New Employee(1797), "John Adams")
empCollection2.Add(New Employee(1801), "Thomas Jefferson")

You retrieve objects from the collection much as you did from the ArrayLists:

For Each i In intCollection
    Console.Write("{0} ", i.ToString( ))
Next i

Dim e As Employee
For Each e In empCollection
    Console.Write("{0} ", e.ToString( ))
Next e

For Each e In empCollection2
    Console.Write("{0} ", e.ToString( ))
Next e

You can, however, retrieve objects from the collection using either the key value or an index value (one-based):

Dim emp As Employee
emp = empCollection2.Item("John Adams")
Console.WriteLine("Key John Adams retrieved empID {0}", emp.ToString( ))

emp = empCollection2.Item(1)
Console.WriteLine("Index(1) retrieved empID {0}", emp.ToString( ))

9.6.3 Queues

A queue represents a first-in, first-out (FIFO) collection. The classic analogy is a line (or queue if you are British) at a ticket window. The first person in line ought to be the first person to come off the line to buy a ticket.

The Queue class is a good collection to use when you are managing a limited resource. For example, you might want to send messages to a resource that can handle only one message at a time. You would then create a message queue so that you can say to your clients: "Your message is important to us. Messages are handled in the order in which they are received."

The Queue class has a number of member methods and properties, the most important of which are shown in Table 9-5.

Table 9-5. Queue members

Method or property

Purpose

Count

Public property that gets the number of elements in the Queue

Clear( )

Method that removes all objects from the Queue

Contains( )

Method that determines if an element is in the Queue

CopyTo( )

Method that copies the Queue elements to an existing one-dimensional array

Dequeue( )

Method that removes and returns the object at the beginning of the Queue

Enqueue( )

Method that adds an object to the end of the Queue

GetEnumerator( )

Method that returns an enumerator for the Queue

Peek( )

Method that returns the object at the beginning of the Queue without removing it

ToArray( )

Method that copies the elements to a new array

You add elements to your queue with the Enqueue( ) method, and you take them off the queue with Dequeue( ) or by using an enumerator. Example 9-15 shows how to use a Queue, followed by the output and a complete analysis.

Example 9-15. Implementing the Queue class
Option Strict On
Imports System

Namespace QueueDemo
    Class Tester
        Public Sub Run( )
            Dim intQueue As New Queue( )

            'populate the array
            Dim i As Integer
            For i = 0 To 4
                intQueue.Enqueue((i * 5))
            Next i

            'display the Queue
            Console.WriteLine("intQueue values:")
            DisplayValues(intQueue)

            'remove an element from the Queue
            Console.WriteLine("(Dequeue) {0}", intQueue.Dequeue( ))

            'display the Queue
            Console.WriteLine("intQueue values:")
            DisplayValues(intQueue)

            'remove another element from the Queue
            Console.WriteLine("(Dequeue) {0}", intQueue.Dequeue( ))

            'display the Queue
            Console.WriteLine("intQueue values:")
            DisplayValues(intQueue)

            'view the first element in the Queue but do not remove
            Console.WriteLine("(Peek)   {0}", intQueue.Peek( ))

            'display the Queue
            Console.WriteLine("intQueue values:")
            DisplayValues(intQueue)
        End Sub 'Run

        Public Shared Sub DisplayValues(ByVal myCollection As IEnumerable)
            Dim myEnumerator As IEnumerator = myCollection.GetEnumerator( )
            While myEnumerator.MoveNext( )
                Console.WriteLine("{0} ", myEnumerator.Current)
            End While
            Console.WriteLine( )
        End Sub 'DisplayValues

        Shared Sub Main( )
            Dim t As New Tester( )
            t.Run( )
        End Sub 'Main
    End Class 'Tester

End Namespace 'QueueDemo

Output:
intQueue values:
0
5
10
15
20

(Dequeue) 0
intQueue values:
5
10
15
20

(Dequeue) 5
intQueue values:
10
15
20

(Peek)   10
intQueue values:
10
15
20

In Example 9-15, the ArrayList from Example 9-13 is replaced by a Queue. I've dispensed with the Employee class and enqueued integers to save room in the book, but of course you can enqueue user-defined objects as well.

The program begins by creating an instance of a Queue, called intQueue:

Dim intQueue As New Queue( )

The queue is populated with integers:

For i = 0 To 4
    intQueue.Enqueue((i * 5))
Next i

The contents of the queue are then displayed using the DisplayValues( ) method. This method takes a collection that implements the IEnumerable interface (as does each of the collections provided by the .NET Framework) and asks that collection for its enumerator. It then explicitly iterates over the collection, displaying each element in turn:

Public Shared Sub DisplayValues(ByVal myCollection As IEnumerable)
    Dim myEnumerator As IEnumerator = myCollection.GetEnumerator( )
    While myEnumerator.MoveNext( )
        Console.Write("{0} ", myEnumerator.Current)
    End While
    Console.WriteLine( )
End Sub 'DisplayValues

You can avoid all the details of the Enumerator by using the For Each loop instead:

Public Shared Sub DisplayValues( _
      ByVal myCollection As IEnumerable)
    Dim o As Object
    For Each o In myCollection
        Console.WriteLine(o)
    Next
End Sub 'DisplayValues

Either version of DisplayValues( ) will work equally well.

You can display the first value in the queue without removing it by calling the Peek( ) method:

Console.WriteLine("(Peek) {0}", intQueue.Peek( ))

Or, having displayed the values in the For Each loop, you can remove the current value by calling the Dequeue( ) method:

Console.WriteLine("(Dequeue) {0}", intQueue.Dequeue( ))

9.6.4 Stacks

A stack is a last-in, first-out (LIFO) collection, like a stack of dishes at a buffet table or a stack of coins on your desk. You add a dish on top, and it is the first dish you take off the stack.

The classic example of a stack is the stack, the portion of memory on which parameters and local variables are stored. See Chapter 5 for more about the stack.

The principal methods for adding to and removing from an instance of the Stack class are Push( ) and Pop( ); Stack also offers a Peek( ) method, very much like Queue. Table 9-6 shows the most important methods and properties for Stack.

Table 9-6. Stack members

Method or property

Purpose

Clear( )

Method that removes all objects from the Stack

Contains( )

Method that determines if an element is in the Stack

CopyTo( )

Method that copies the Stack elements to an existing one-dimensional array

Count

Public property that gets the number of elements in the Stack

GetEnumerator( )

Method that returns an enumerator for the Stack

Peek( )

Method that returns the object at the top of the Stack without removing it

Pop( )

Method that removes and returns the object at the top of the Stack

Push( )

Method that inserts an object at the top of the Stack

ToArray( )

Method that copies the elements to a new array

In Example 9-16, you rewrite Example 9-15 to use a Stack rather than a Queue. The logic is almost identical. The key difference is that a Stack is Last In, First Out, while a Queue is First In, First Out.

Example 9-16. Using a Stack
Option Strict On
Imports System

Namespace StackDemo
    Class Tester
        Public Sub Run( )
            Dim intStack As New Stack( )

            'populate the stack
            Dim i As Integer
            For i = 0 To 7
                intStack.Push((i * 5))
            Next i

            'display the Stack
            Console.WriteLine("intStack values:")
            DisplayValues(intStack)

            'remove an element from the stack
            Console.WriteLine("(Pop){0}", intStack.Pop( ))

            'display the Stack
            Console.WriteLine("intStack values:")
            DisplayValues(intStack)

            'remove another element from the stack
            Console.WriteLine("(Pop){0}", intStack.Pop( ))

            'display the Stack
            Console.WriteLine("intStack values:")
            DisplayValues(intStack)

            'view the first element in the 
            ' Stack but do not remove
            Console.WriteLine("(Peek)   {0}", intStack.Peek( ))

            'display the Stack
            Console.WriteLine("intStack values:")
            DisplayValues(intStack)
        End Sub 'Run

        Public Shared Sub DisplayValues(ByVal myCollection As IEnumerable)
            Dim o As Object
            For Each o In myCollection
                Console.WriteLine(o)
            Next o
        End Sub 'DisplayValues

        Shared Sub Main( )
            Dim t As New Tester( )
            t.Run( )
        End Sub 'Main
    End Class 'Tester

End Namespace 'StackDemo

Output:
intStack values:
35
30
25
20
15
10
5
0
(Pop)35
intStack values:
30
25
20
15
10
5
0
(Pop)30
intStack values:
25
20
15
10
5
0
(Peek)   25
intStack values:
25
20
15
10
5
0

You start Example 9-16 by creating a Stack object called intStack:

Dim intStack As New Stack( )

You populate the stack with integers by calling the Push( ) method, which pushes each integer object onto the stack (i.e., adds it to the top of the Stack):

For i = 0 To 7
    intStack.Push((i * 5))
Next i

You remove an object from the stack by popping it off the stack with the Pop( ) method:

Console.WriteLine("(Pop){0}", intStack.Pop( ))

Just as you could peek at the object at the beginning of the Queue without dequeing it, you can Peek( ) at the object on top of the stack without popping it:

Console.WriteLine("(Peek)   {0}", intStack.Peek( ))

  Previous section   Next section
Top