TopFor loopsArrays

Arrays

Sometimes we have a lot of very similar data, and we would like to do similar things to each datum. For example, last week we looked at a program in which we had a bunch of balls, each of which moved a bit to simulate a chain reaction.

Now consider another example. In the Frogger program we had many images of cars, and it would have been nice if we had been able to pass them in to a Lane as a group and then randomly select a new image each time for generating new cars. You might imagine how to make a collection of car images using a linked list. But how would you go about randomly selecting an image from that collection? If we could consider the images as a group and talk about the first, second, third, ..., elements of the group then we could randomly choose a number n, and then ask for the nth element of the group. This could certainly be done with a linked list, but there is an even better data structure for doing this.

In mathematics this is done by attaching subscripts to names. We can talk about numbers n1, n2,... We want to be able to do the same thing with computer languages. The name for this type of group of elements is an array.

Suppose we wish to have a group of elements all of which have type ThingAMaJig and we wish to call the group things. Then we write the declaration of things as

    ThingAMaJig[] things;
The only difference between this and the declaration of a single item of type ThingAMaJig is the occurrence of "[ ]" after the type.

Like all other objects, a group of elements needs to be created:

    things = new ThingAMaJig[25];
Again, notice the square brackets. The number in parentheses (25) indicates the maximum number of elements that there are slots for. We can now refer to individual elements using subscripts. However, in programming languages we cannot easily set the subscripts in a smaller font placed slightly lower than regular type. As a result we use the ubiquitous "[ ]" to indicate a subscript. If, as above, we define things to have 25 elements, they may be referred to as:
    things[0], things[1], ..., things[24]
We start numbering the subscripts at 0, and hence the last subscript is one smaller than the total number of elements. Thus in the example above the subscripts go from 0 to 24.

One warning: When we initialize an array as above, we only create slots for all of the elements, we do not necessarily fill the slots with elements. Actually, the default values of the elements of the array are the same as for instance variables of the same type. If ThingAMaJig is an object type, then the initial values of all elements is null, while if it is int, then the initial values will all be 0. Thus you will want to be careful to put the appropriate values in the array before using them (esp. before sending message to them!).

Below are some excerpts from a program that provides a slide show: Demo. Slide Show

public class Slides extends WindowController implements ActionListener
{
    private static final int numSlides = 7;  // number of slides to be shown
    private Image[] image;              // array of images for slides
    private VisibleImage[] slide;      // array of visible images for slides
    ...
    begin()
    {
        image = new Image[numSlides];

        // Load the images
        image[0] = getImage("Bailey.gif");
        image[1] = getImage("Bruce.gif");
        image[2] = getImage("Danyluk.gif");
        image[3] = getImage("Lenhart.gif");
        image[4] = getImage("Lerner.gif");
        image[5] = getImage("Murtagh.gif");
        image[6] = getImage("Teresco.gif");
        
        slide = new VisibleImage[numSlides];   // Create (and hide) visible 
                                                // images
        for (int counter = 0; counter < numSlides; counter++)
        {
            slide[counter]= new VisibleImage(image[counter],
                                              XIMAGE,YIMAGE,canvas);
            slide[counter].hide();
        }
        ...
    }    

In this code excerpt there are two arrays: image is an array of objects of type Image, while slide is an array of type VisibleImage. Each is created to have numSlides elements. The elements in images are initialized individually using getImage(...), while the elements of slide are initialized in a for loop. For loops are frequently used with arrays since the for loop makes it easy to cycle through all of the elments of the array.

Also note that we can send messages (like hide) to individual elements of an array, just as we did with regular variables. By way of contrast, we could not write slide.hide() because slide is not an element of type VisibleImage. It is instead an array, and arrays only allow access to their individual components.

Later on in the program, if we wanted to, we could display a different (randomly selected) slide whenever a button is pushed:

    public void actionPerformed(ActionEvent event)
    {
        slide[current].hide();          // hide last slide
        current = slideGen.nextValue(); // randomly select new slide
        slide[current].show();          // show it
    }

We could also have buttons that allow the user to walk through the slide show in order, either forward or backward. This is the version you'll see in the demo.

There are two buttons available named next and previous:

    public void actionPerformed(ActionEvent event)
    {
        slide[counter].hide();          // hide last slide
        if(event.getSource() == next)   // get next (or previous) slide 
        {                               // (wrapping if necessary)
            counter = (counter + 1) % numSlides;                                
        }
        else
        {
            counter = (counter + numSlides - 1) % numSlides;    
        }
        slide[counter].show();
    }
Notice how easy it is to move from one element to the next with an array. Let us first take a look at what happens if the next button is pushed. If counter starts out at 0, then slide[0] is hidden, counter is increased by 1, and then slide[1] is shown.

The statement counter = (counter + 1) % numSlides may need a bit of explanation. The symbol "%" represents the "mod" operator. If m and n are ints, then m%n represents the remainder after dividing m by n. In the above program numSlides is 7. Clearly 1%7 = 1, 2%7 = 2, etc., but something interesting happens for the first time when counter is 6. When counter = (counter + 1) % numSlides is executed, counter + 1 evaluates to 7, and 7 % numSlides is 0. Hence if we look through the sequence of values that counter takes on when the user clicks on the next button, we see that it is 0, 1, 2, 3, ..., 6, 0, 1, 2, ... Thus we normally go up by 1, but when we pass 6 the value automatically goes back to 0.

We leave as an exercise for the reader to figure out what happens when we execute counter = (counter + numSlides - 1) % numSlides when the previous button is clicked repeatedly. We simply note that you might have expected to see counter = (counter - 1) % numSlides, but that would not work because if n is a negative number n%m returns a non-positive number. In particular, -1%7 evaluates to -1. In order to force it to be positive, we always add numSlides. Try it out by hand to see the sequence of values obtained.

In the above program, we knew exactly how many elements were held in the array, but it is often the case that while we know the maximum number of elements to be held, there usually are fewer than the maximum in the array at any one time.


TopFor loopsArrays