Chapter 16. Using Arrays and Collections

The data types described in previous lessons each hold a single piece of data. A variable might hold an integer, a string, or a point in time.

Sometimes it's convenient to work with a group of related values all at once. For example, suppose you're the CEO of a huge company that just posted huge losses. In that case, you might want to give each hourly employee a 10 percent pay cut and give each executive a 15 percent bonus.

In cases like this, it would be handy to be able to store all the hourly employee data in one variable so you could easily work with it. Similarly, you might like to store the executives' data in a second variable so it's easy to manage.

In this lesson, you learn how to make variables that can hold more than one piece of data. You learn how to make arrays and different kinds of collections such as Lists, Dictionaries, Stacks, and Queues.

This lesson explains how to build these objects and add and remove items from them. Lesson 19 explains how to get the full benefit of them by looping through them to perform some action on each of the items they contain.

ARRAYS

An array is a group of values that all have the same data type and that all share the same name. Your code uses an index, which is an integer greater than or equal to 0, to pick a particular item in the array.

An array is analogous to the mailboxes in an apartment building. The building has a single bank of mailboxes that all have the same street address (the array's name). You use the apartment numbers to pick a particular cubbyhole in the bank of mailboxes.

Figure 16-1 shows an array graphically. This array is named values. It contains eight entries with indexes 0 through 7.

FIGURE 16-1

Figure 16.1. FIGURE 16-1

Note

An array's smallest and largest indexes are called its lower bound and upper bound, respectively. In Visual Basic, the lower bound is always 0, and the upper bound is always one less than the length of the array.

Creating Arrays

The following code shows how you might create an array of integers. The parentheses and the number 8 mean this should be an array with bounds 0 and 8, giving it 9 items.

Dim values(8) As Integer

You can optionally include the phrase "0 To" before the upper bound to emphasize the fact that array has 0 for its lower bound, as in the following code:

Dim values(0 To 8) As Integer

Warning

Don't get confused and think the number inside the array declaration (in this case, 8) is the array's length. That number is the array's upper bound, so its length is one greater than this number. Adding "0 To" may make this easier to remember.

Alternatively, you can declare an array without giving it an upper bound. Later you can use the ReDim statement to redimension the array and give it bounds. For example, the following code declares an array of strings named employees. Later it uses ReDim to give the array 100 entries.

Dim employees() As String
...
ReDim employees(0 To 99)

If you include the optional Preserve keyword, then the array retains any old values when it resizes. If you don't include Preserve, then all of the entries in the array are reset to default values such as 0 for numbers and a blank string for strings.

For example, the following code shrinks the employees array to hold only 50 values, keeping the entries in positions 0 through 49:

ReDim Preserve employees(0 To 49)

After you have created an array, you can access its members by using the array's name followed by an index inside parentheses. For example, the following code initializes the values array by setting the Nth entry equal to N squared:

values(0) = 0 * 0
values(1) = 1 * 1
values(2) = 2 * 2
values(3) = 3 * 3
values(4) = 4 * 4
values(5) = 5 * 5
values(6) = 6 * 6
values(7) = 7 * 7
values(8) = 8 * 8

Note

Most programmers pronounce values(5) as "values of 5," "values sub 5," or "the fifth element of values."

After you have placed values in an array, you can read the values using the same parentheses syntax. The following code displays a message box that uses one of the array's values:

MessageBox.Show("7 * 7 is " & values(7).ToString())

To make initializing arrays easier, Visual Basic provides an abbreviated syntax that lets you declare an array and set its values all in one statement. Simply set the variable equal to the values you want separated by commas and surrounded by braces, as shown in the following code:

Dim values() As Integer = {0, 1, 1, 2, 3, 5, 8, 13, 21, 34}

Note that you cannot include an upper bound when you initialize an array in this way. Visual Basic figures out the upper bound based on the number of values you provide.

When the user clicks Calculate, the program executes the following code:

' Display a Fibonacci number.
Private Sub btnCalculate_Click() Handles btnCalculate.Click
    Dim values(0 To 20) As Integer
    values(0) = 0
    values(1) = 1
    values(2) = values(0) + values(1)
    values(3) = values(1) + values(2)
    ...

    Dim index As Integer = CInt(nudIndex.Value)
    txtResult.Text = values(index).ToString()
End Sub

The code starts by initializing the values array to hold the first 21 Fibonacci numbers. It uses the following definition of the numbers to calculate the values:

Fibonacci(i) = Fibonacci(i - 1) + Fibonacci(i - 2)

After initializing the array, the program gets the value selected by the NumericUpDown control, converts it from a Decimal to an Integer, uses it as an index into the values array, and displays the result in txtResult.

Multi-Dimensional Arrays

The arrays described in the previous section hold a single row of items but Visual Basic also enables you to define multi-dimensional arrays. You can think of these as higher dimensional sequences of apartment mailboxes.

Figure 16-3 shows a graphic representation of a two-dimensional array with four rows and eight columns.

FIGURE 16-3

Figure 16.3. FIGURE 16-3

The following code shows how you could declare, allocate, and initialize this array to hold a multiplication table with values up to 3 times 7:

Dim values(0 To 3, 0 To 7) As Integer
values(0, 0) = 0 * 0
values(0, 1) = 0 * 1
values(0, 2) = 0 * 2
...
values(1, 0) = 1 * 0
values(1, 1) = 1 * 1
...
values(3, 7) = 3 * 7

The following code shows the Visual Basic syntax for quickly defining and initializing a two-dimensional array:

Dim values(,) As Integer =
{
    {0, 1, 2},
    {3, 4, 5},
    {6, 7, 8}
}

You can use similar syntax to make and initialize even higher-dimensional arrays. For example, the following code makes a four-dimensional array of strings:

Dim employeeData(0 To 9, 0 To 19, 0 To 29, 0 To 39) As String

Array Properties and Methods

All arrays have a Length property that your code can use to determine the number of items in the array. All arrays have a lower bound of 0, so for one-dimensional arrays, Length – 1 gives an array's upper bound.

Arrays also have GetLowerBound and GetUpperBound methods that return the lower and upper bounds, respectively, for a particular dimension in an array.

For example, the following code creates a 5-by-10 array. It then displays the lower and upper bounds for the two dimensions. (As usual, the dimension numbers start at 0.)

Dim x(4, 9) As Integer
MessageBox.Show("The first dimension runs from " &
    x.GetLowerBound(0) & " to " & x.GetUpperBound(0))
MessageBox.Show("The second dimension runs from " &
    x.GetLowerBound(1) & " to " & x.GetUpperBound(1))

The Array class also provides several useful static methods that you can use to manipulate arrays. For example, the following code sorts the array named salaries:

Array.Sort(salaries)

Note

To sort an array, the array must contain things that can be compared in a meaningful way. For example, Integer and String data have a natural order, so it's easy to say that the string "Jackson" should come before the string "Utah."

If an array holds Employee objects, however, it's unclear how you would want to compare two items. In fact, it's likely that you couldn't define an order that would always work because sometimes you might want to sort employees by name and other times you might want to sort them by employee ID or even salary.

You can solve this problem in a couple of ways, including the IComparer interface (mentioned briefly in Lesson 29's Exercise 2) and making the Employee class implement IComparable (mentioned in Lesson 30). These are slightly more advanced topics, so they aren't covered in great depth here.

The Sort method has many overloaded versions that perform different kinds of sorting. For example, instead of passing it a single array, you can pass it an array of keys and an array of items. In that case the method sorts the keys, moving the items so they remain matched up with their corresponding keys.

Table 16-1 summarizes the most useful methods provided by the Array class.

Table 16.1. TABLE 16-1

METHOD

PURPOSE

BinarySearch

Uses binary search to find an item in a sorted array

Clear

Resets a range of items in the array to the default value for the array's data type (for example, 0, False, or Nothing)

Copy

Copies a range of items from one array to another

IndexOf

Returns the index of a particular item in the array

LastIndexOf

Returns the index of the last occurrence of a particular item in the array

Resize

Resizes the array, preserving any items that fit in the new size

Reverse

Reverses the order of the items in the array

Sort

Sorts the array's items

COLLECTION CLASSES

An array holds a group of items and lets you refer to them by index. The .NET Framework also provides an assortment of collection classes that you can use to store and manipulate items in other ways. For example, a Dictionary stores items with keys and lets you very quickly locate an item from its key. You could use a Dictionary to make an employee phone book and very quickly look up a phone number by employee name.

Generic Classes

The following sections describe some particular kinds of classes that are included pre-built by the .NET Framework. These are generic classes so before you learn about them you should know a little about what a generic class is.

A generic class is one that is not tied to a particular data type. For example, suppose you built a StringList class that can store a list of strings. Now suppose you decided you wanted an IntegerList class to store lists of integers. The two classes would be practically identical, just for different data types.

I've mentioned several times that duplicated code is a bad thing. Having two nearly identical classes means debugging and maintaining two different sets of code that are practically the same.

One solution to this dilemma is to make a more general AnythingList class that uses the general Object data type to store items. An Object can hold any kind of data, so this class could hold lists of integers, strings, or Customer objects. Unfortunately, this solution has two big problems.

First, you would do a lot of work converting the items with the general Object data type stored in the list into the Integer, String, or Customer type of the items that you put in there. This is annoying because it gives you more work to do, and it makes your code more complicated and harder to read.

A bigger problem is that a list that can hold anything can hold anything. If you make a list intended to hold customer data, it could still hold Integers, Strings, and PurchaseOrder objects. Your code would need to do a lot of work to protect against potentially invalid data.

A much better approach is to use generic classes. These classes take data types in their declarations so they know what kind of data they will manipulate. Using this kind of class, you can use the same class to build a list of integers, strings, or what have you.

The following code declares and initializes a generic List class:

Dim names As New List(Of String)

The (Of String) part of the declaration indicates that the class will work with strings. You can put strings into the list and take strings out of it. You cannot add an integer to the list, just as you can't set a string variable equal to an integer. Visual Studio knows that the list works with strings and not with anything else.

Note that IntelliSense recognizes generic classes and provides help. If you begin a declaration with List, IntelliSense displays List(Of T) to let you know that it is a generic class.

Now, with some understanding of generic classes, you're ready to look at some generic collection classes.

Lists

A List is a simple ordered list of items. You can declare and initialize a List as shown in the following code:

Dim names As New List(Of String)

The List class provides several methods for manipulating the items it contains. The three most important are Add, Remove, and RemoveAt:

  • The Add method adds a new item to the end of the List, automatically resizing the List if necessary. This is easier than adding an item to an array, which requires you to resize the array first.

  • The Remove method removes a particular item from the List. Note that you pass the target item to Remove, not the index of the item that you want to remove. If you know that the string "Zaphod" is in the List names, the following code removes the first instance of that name from the List:

    names.Remove("Zaphod")

    Note

    The Remove method removes only the first occurrence of an item from the List.

  • The RemoveAt method removes an item from a particular position in the List. It then compacts the List to remove the hole where the item was. This is much easier than removing an item from an array, which requires you to shuffle items from one part of the array to another and then resize the array to reduce its size.

In addition to these methods, you can use parentheses to get and set a List's entries much as you can with an array. For example, the following code sets and then displays the value of the first entry in a List:

names(0) = "Mickey"
MessageBox.Show("The first name is " & names(0))

Note that this works only if the index you use exists in the List. If the list holds 10 names and you try to set the 14th, the program crashes.

SortedLists

A SortedList stores a list of key/value pairs, keeping the list sorted by the keys. The types of the keys and values are generic parameters; for example, you could make a list that uses numbers (such as employee IDs) for keys, and strings (such as names) for values.

Note that the list will not allow you to add two items with the same key. Multiple items can have the same value, but if you try to add two with the same key, the program crashes.

Table 16-2 summarizes useful methods provided by the SortedList class.

Table 16.2. TABLE 16-2

METHOD

PURPOSE

Add

Adds a key and value to the list

Clear

Empties the list

Contains

Returns True if the list contains a given value

ContainsKey

Returns True if the list contains a given key

ContainsValue

Returns True if the list contains a given value

GetKeyList

Returns a list holding the keys

GetValueList

Returns a list holding the values

Remove

Removes the item with a specific key from the list

In addition to these methods, you can use parentheses to index into the list, using the items' keys as indexes.

The following code demonstrates a SortedList:

Dim addresses As New SortedList(Of String, String)

addresses.Add("Dan", "4 Deer Dr, Bugville VT, 01929")
addresses.Add("Bob", "8273 Birch Blvd, Bugville VT, 01928")

addresses("Cindy") = "32878 Carpet Ct, Bugville VT, 01929"
addresses("Alice") = "162 Ash Ave, Bugville VT, 01928"
addresses("Bob") = "8273 Bash Blvd, Bugville VT, 01928"

MessageBox.Show("Bob's address is " & addresses("Bob"))

The code starts by declaring and initializing the list. It uses the Add method to add some entries and then uses parentheses to add some more. Notice that the SortedList doesn't need to already contain a key before the code can set its value. In this example, there is no entry for Cindy until the code sets addresses("Cindy".

Next, the code uses the parentheses syntax to update Bob's address. Finally, the code displays Bob's new address.

You can't see it from this example, but unlike the List class, SortedList actually stores its items ordered by key. For example, you could use the GetKeyList and GetValueList methods to get the SortedList's keys and values in order.

Dictionaries

The Dictionary and SortedDictionary classes provide features similar to the SortedList class, manipulating key/value pairs. The difference is in the data structures the three classes use to store their items.

Without getting into technical details, the result is that the three classes use different amounts of memory and work at different speeds. In general, SortedList is the slowest but takes the least memory, while Dictionary is the fastest but takes the most memory.

For small programs, the difference is insignificant. For big programs that work with thousands of entries, you might need to be more careful about picking a class. (Personally, I like Dictionary for most purposes because speed is nice, memory is relatively cheap, and the name is suggestive of the way you use the class: to look up something by key.)

Queues

A Queue is a collection that enables you to add items at one end and remove them from the other. It's like the line at a bank; you stand at the back of the line and the teller helps the person at the front of the line until eventually it's your turn.

Note

Because a queue retrieves items in first-in-first-out order, queues are sometimes called FIFO lists or FIFOs. ("FIFO" is pronounced fife-o.)

Table 16-3 summarizes the Queue's most important methods.

Table 16.3. TABLE 16-3

METHOD

PURPOSE

Clear

Removes all items from the Queue

Dequeue

Returns the item at the front of the Queue and removes it

Enqueue

Adds an item to the back of the Queue

Peek

Returns the item at the front of the Queue without removing it

Stacks

A Stack is a collection that enables you to add items at one end and remove them from the same end. It's like a stack of books on the floor: You can add a book to the top of the stack and remove a book from the top, but you can't pull one out of the middle or bottom without risking a collapse.

Note

Because a stack retrieves items in last-in-first-out order, stacks are sometimes called LIFO lists or LIFOs. ("LIFO" is pronounced life-o.)

The top of a stack is also sometimes called its head. The bottom is sometimes called its tail.

Table 16-4 summarizes the Stack's most important methods.

Table 16.4. TABLE 16-4

METHOD

PURPOSE

Clear

Removes all items from the Stack

Peek

Returns the item at the top of the Stack without removing it

Pop

Returns the item at the top of the Stack and removes it

Push

Adds an item to the top of the Stack

TRY IT

In this Try It, you use a Dictionary to build the order lookup system shown in Figure 16-4. When the user clicks the Add button, the program adds a new item with the given order ID and items. If the user enters an order ID and clicks Find, the program retrieves the corresponding items. If the user enters an order ID and some items and then clicks Update, the program updates the order's items.

FIGURE 16-4

Figure 16.4. FIGURE 16-4

Note

You can download the code and resources for this Try It from the book's web page at www.wrox.com or www.vb-helper.com/24hourvb.html. You can find them in the Lesson16 folder in the download.

Lesson Requirements

In this lesson:

  • Create the form shown in Figure 16-4.

  • Add code that creates a Dictionary field named Orders. Set its generic type parameters to Integer (for order ID) and String (for items).

  • Add code to the Add button that creates the new entry in the dictionary.

  • Add code to the Find button that retrieves the appropriate entry from the dictionary.

  • Add code to the Update button to update the indicated entry.

Warning

This program will be fairly fragile and will crash if you don't enter an order ID, enter an ID that is not an integer, try to enter the same ID twice, try to find a nonexistent ID, and so forth. Don't worry about these problems. You learn how to handle them later, notably in Lessons 18 and 21.

Step-by-Step

  • Create the form shown in Figure 16-4.

    1. This is relatively straightforward. The only tricks are to set the Items TextBox's MultiLine and AcceptsReturn properties to True.

  • Add code that creates a Dictionary named orders. Set its generic type parameters to Integer (for order ID) and String (for items).

    1. Use code similar to the following to make the Orders field:

      ' The dictionary to hold orders.
      Private Orders As New Dictionary(Of Integer, String)()
  • Add code to the Add button that creates the new entry in the dictionary.

    1. This code should call the Dictionary's Add method, passing it the order ID and items entered by the user. Use Integer.Parse to convert the ID entered by the user into an Integer.

      Optionally, you can add code to clear the textboxes to get ready for the next entry. The code could be similar to the following:

      ' Add the order data.
      Orders.Add(Integer.Parse(txtOrderId.Text), txtItems.Text)
      
      ' Get ready for the next one.
      txtOrderId.Clear()
      txtItems.Clear()
      txtOrderId.Focus()
  • Add code to the Find button that retrieves the new appropriate entry from the dictionary.

    1. Use code similar to the following:

      txtItems.Text = Orders(Integer.Parse(txtOrderId.Text))
  • Add code to the Update button to update the indicated entry.

    1. Use code similar to the following:

      Orders(Integer.Parse(txtOrderId.Text)) = txtItems.Text

Note

Please select Lesson 16 on the DVD to view the video that accompanies this lesson.

EXERCISES

  1. Make a program similar to the Fibonacci program that looks up factorials in an array. When the program starts, make it create the array to hold the first 20 factorials. Use the following definition for the factorial (where N! means the factorial of N):

    0! = 1
    N! = N * (N - 1)!
  2. Make a program that demonstrates a stack of strings. The program should display a textbox and two buttons labeled Push and Pop. When the user clicks Push, add the current text to the stack. When the user clicks Pop, remove the next item from the stack and display it in the textbox.

  3. Make a program that demonstrates a queue of strings. The program should display a textbox and two buttons labeled Enqueue and Dequeue. When the user clicks Enqueue, add the current text to the queue. When the user clicks Dequeue, remove the next item from the queue and display it in the textbox.

  4. Make a program similar to the one you built for this lesson's Try It except make it store appointment information. The Dictionary should use the Date type for keys and the String type for values. Let the user pick dates from a DateTimePicker.

    Hint: When the DateTimePicker first starts, it defaults to the current time, which may include fractional seconds. After the user changes the control's selection, however, the value no longer includes fractional seconds. That makes it hard to search for the exact same date and time later, at least if the user enters a value before changing the control's initial value.

    To avoid this problem, when the form loads, initialize the DateTimePicker to a value that doesn't include fractional seconds. Use the properties provided by Date.Now to create a new Date without fractional seconds and set the DateTimePicker's value to that.

  5. Make a day planner application. The code should make an array of 31 strings to hold each day's plan. Initialize the array to show fake plans such as "Day 1."

    Use a ComboBox to let the user select a day of the month. When the ComboBox's value changes, display the corresponding day's plan in a large TextBox on the form.

    Hint: Use the ComboBox's SelectedIndex property as an index into the array. Note that this program doesn't let the user enter or modify the plan, it just displays hardcoded values. To let the user modify the plan, you would need Find and Update buttons similar to those used in other exercises.

    Hint: To make the DateTimePicker display date and time, set its Format property to Custom and set its CustomFormat property to ddd dd MMM yyyy h:mm tt.

Note

You can find solutions to this lesson's exercises in the Lesson16 folder inside the download available on the book's web site at www.wrox.com or www.vb-helper.com/24hourvb.html.

EXERCISES
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset