Chapter 4. Arrays

Putting Some Order in Your Data

image with no caption

There’s more to JavaScript than numbers, strings and booleans. So far you’ve been writing JavaScript code with primitives—simple strings, numbers and booleans, like “Fido”, 23, and true. And you can do a lot with primitive types, but at some point you’ve got to deal with more data. Say, all the items in a shopping cart, or all the songs in a playlist, or a set of stars and their apparent magnitude, or an entire product catalog. For that we need a little more ummph. The type of choice for this kind of ordered data is a JavaScript array, and in this chapter we’re going to walk through how to put your data into an array, how to pass it around and how to operate on it. We’ll be looking at a few other ways to structure your data in later chapters but let’s get started with arrays.

image with no caption

Can you help Bubbles-R-Us?

Meet the Bubbles-R-Us company. Their tireless research makes sure bubble wands & machines everywhere blow the best bubbles. Today they’re testing the “bubble factor” of several variants of their new bubble solution; that is, they’re testing how many bubbles a given solution can make. Here’s their data:

image with no caption

Of course you want to get all this data into JavaScript so you can write code to help analyze it. But that’s a lot of values. How are you going to construct your code to handle all these values?

How to represent multiple values in JavaScript

You know how to represent single values like strings, numbers and booleans with JavaScript, but how do you represent multiple values, like all the bubble factor scores from the ten bubble solutions? To do that we use JavaScript arrays. An array is a JavaScript type that can hold many values. Here’s a JavaScript array that holds all the bubble factor scores:

image with no caption

You can treat all the values as a whole, or you can access the individual scores when you need to. Check this out:

image with no caption
image with no caption

How arrays work

Before we get on to helping Bubbles-R-Us, let’s make sure we’ve got arrays down. As we said, you can use arrays to store multiple values (unlike variables that hold just one value, like a number or a string). Most often you’ll use arrays when you want to group together similar things, like bubble factor scores, ice cream flavors, daytime temperatures or even the answers to a set of true/false questions. Once you have a bunch of values you want to group together, you can create an array that holds them, and then access those values in the array whenever you need them.

image with no caption

How to create an array

Let’s say you wanted to create an array that holds ice cream flavors. Here’s how you’d do that:

image with no caption

When you create an array, each item is placed at a location, or index, in the array. With the flavors array, the first item, “vanilla”, is at index 0, the second, “butterscotch”, is at index 1, and so on. Here’s a way to think about an array:

image with no caption

How to access an array item

Each item in the array has its own index, and that’s your key to both accessing and changing the values in an array. To access an item just follow the array variable name with an index, surrounded by square brackets. You can use that notation anywhere you’d use a variable:

image with no caption

Updating a value in the array

You can also use the array index to change a value in an array:

image with no caption

So, after this line of code, your array will look like this:

How big is that array anyway?

Say someone hands you a nice big array with important data in it. You know what’s in it, but you probably won’t know exactly how big it is. Luckily, every array comes with its own property, length. We’ll talk more about properties and how they work in the next chapter, but for now, a property is just a value associated with an array. Here’s how you use the length property:

image with no caption
image with no caption

You didn’t think our serious business application from Chapter 1 was serious enough? Fine. Try this one, if you need something to show the boss.

image with no caption

The Phrase-O-Matic

We hope you figured out this code is the perfect tool for creating your next start-up marketing slogan. It has created winners like “Win-win value-added solution” and “24/7 empowered process” in the past and we have high hopes for more winners in the future. Let’s see how this thing really works:

  1. First, we define the makePhrases function, which we can call as many times as we want to generate the phrases we want:

    image with no caption
  2. With that out of the way we can write the code for the makePhrases function. Let’s start by setting up three arrays. Each will hold words that we’ll use to create the phrases. In the next step, we’ll pick one word at random from each array to make a three word phrase.

    image with no caption
  3. Now we generate three random numbers, one for each of the three random words we want to pick to make a phrase. Remember from Chapter 2 that Math.random generates a number between 0 and 1 (not including 1). If we multiply that by the length of the array, and use Math.floor to truncate the number, we get a number between 0 and one less than the length of the array.

    image with no caption
  4. Now we create the slick marketing phrase by taking each randomly chosen word and concatenating them all together, with a nice space in between for readability:

    image with no caption
  5. We’re almost done; we have the phrase, now we just have to display it. We’re going to use alert as usual.

    alert(phrase);
  6. Okay, finish that last line of code, have one more look over it all and feel that sense of accomplishment before you load it into your browser. Give it a test drive and enjoy the phrases.

    image with no caption

Meanwhile, back at Bubbles-R-Us...

image with no caption

Let’s take a closer look at what the CEO is looking for:

image with no caption

Brain Power

Take some time to sketch out your ideas of how you’d create this little bubble score report. Take each item in the report separately and think of how you’d break it down and generate the right output. Make your notes here.

Cubicle Conversation

image with no caption

Judy: The first thing we need to do is display every score along with its solution number.

Joe: And the solution number is just the index of the score in the array, right?

Judy: Oh, yeah, that’s totally right.

Frank: Slow down a sec. So we need to take each score, print its index, which is the bubble solution number, and then print the corresponding score.

Judy: You’ve got it, and the score is just the corresponding value in the array.

Joe: So, for bubble solution #10, its score is just scores[10].

Judy: Right.

Frank: Okay, but there are a lot of scores. How do we write code to output all of them?

Judy: Iteration, my friend.

Frank: Oh, you mean like a while loop?

Judy: Right, we loop through all the values from zero to the length... oh, I mean the length minus one of course.

Joe: This is starting to sound very doable. Let’s write some code; I think we know what we’re doing.

Judy: That works for me! Let’s do it, and then we’ll come back to the rest of the report.

How to iterate over an array

image with no caption

Your goal is to produce some output that looks like this:

image with no caption

We’ll do that by outputting the score at index zero, and then we’ll do the same for index one, two, three and so on, until we reach the last index in the array. You already know how to use a while loop; let’s see how we can use that to output all the scores:

Note

And then we’ll show you a better way in a sec...

image with no caption

But wait, there’s a better way to iterate over an array

We should really apologize. We can’t believe it’s already Chapter 4 and we haven’t even introduced you to the for loop. Think of the for loop as the while loop’s cousin. The two basically do the same thing, except the for loop is usually a little more convenient to use. Check out the while loop we just used and we’ll see how that maps into a for loop.

image with no caption

Now let’s look at how the for loop makes all that so much easier:

image with no caption
image with no caption
image with no caption

Test drive the bubble report

Save this file as “bubbles.html” and load it into your browser. Make sure you’ve got the console visible (you might need to reload the page if you activate the console after you load the page), and check out the brilliant report you just generated for the Bubbles-R-Us CEO.

image with no caption

It’s that time again.... Can we talk about your verbosity?

image with no caption

You’ve been writing lots of code that looks like this:

image with no caption

In fact, this statement is so common there’s a shortcut for it in JavaScript. It’s called the post-increment operator, and despite its fancy name, it is quite simple. Using the post-increment operator, we can replace the above line of code with this:

image with no caption

Of course it just wouldn’t feel right if there wasn’t a post-decrement operator as well. You can use the post-decrement operator on a variable to reduce its value by one. Like this:

image with no caption

And why are we telling you this now? Because it’s commonly used with for statements. Let’s clean up our code a little using the post-increment operator...

Redoing the for loop with the post-increment operator

Let’s do a quick rewrite and test to make sure the code works the same as before:

image with no caption

Quick test drive

Time to do a quick test drive to make sure the change to use the post-increment operator works. Save your file, “bubbles.html”, and reload. You should see the same report you saw before.

image with no caption

Cubicle Conversation Continued...

image with no caption
image with no caption

Judy: Right, and the first thing we need to do is determine the total number of bubble tests. That’s easy; it’s just the length of the scores array.

Joe: Oh, right. We’ve got to find the highest score too, and then the solutions that have the highest score.

Judy: Yeah, that last one is going to be the toughest. Let’s work out finding the highest score first.

Joe: Sounds like a good place to start.

Judy: To do that I think we just need to maintain a highest score variable that keeps track as we interate through the array. Here, let me write some pseudocode:

image with no caption

Joe: Oh nice; you did it with just a few lines added to our existing code.

Judy: Each time through the array we look to see if the current score is greater than highScore, and if so, that’s our new high score. Then, after the loop ends we just display the high score.

image with no caption

“More than one”...hmmm. When we need to store more than one thing what do we use? An array, of course. So can we iterate through the scores array looking for only scores that match the highest score, and then add them to an array that we can later display in the report? You bet we can, but to do that we’ll have to learn how to create a brand new, empty array, and then understand how to add new elements to it.

image with no caption

Creating an array from scratch (and adding to it)

image with no caption

Before we take on finishing this code, let’s get a sense for how to create a new array, and how to add new items to it. You already know how to create an array with values, like this:

image with no caption

But you can also omit the initial items and just create an empty array:

image with no caption

And you already know how to add new values to an array. To do that you just assign a value to an item at an index, like this:

image with no caption

Now when adding new items you have to be careful about which index you’re adding. Otherwise you’ll create a sparse array, which is an array with “holes” in it (like an array with values at 0 and 2, but no value at 1). Having a sparse array isn’t necessarily a bad thing, but it does require special attention. For now, there’s another way to add new items without worrying about the index, and that’s push. Here’s how it works:

image with no caption
image with no caption

Judy: Yes, we’ll start with an empty array to hold the solutions with the highest scores, and add each solution that has that high score one at a time to it as we iterate through the scores array.

Frank: Great, let’s get started.

Judy: But hold on a second... I think we might need a separate loop.

Frank: We do? Seems like there should be a way to do it in our existing loop.

Judy: Yup, I’m sure we do. Here’s why. We have to know what the highest score is before we can find all the solutions that have that highest score. So we need two loops: one to find the highest score, which we’ve already written, and then a second one to find all the solutions that have that score.

Frank: Oh, I see. And in the second loop, we’ll compare each score to the highest score, and if it matches, we’ll add the index of the bubble solution score to the new array we’re creating for the solutions with the highest scores.

Judy: Exactly! Let’s do it.

Brain Power

Take a look at the code in the Sharpen exercise above. What if you woke up and push no longer existed? Could you rewrite this code without using push? Work that code out here:

Test drive the final report

Go ahead and add the code to generate the bubble solutions with the highest score to your code in “bubbles.html” and run another test drive. All the JavaScript code is shown below:

var scores = [60, 50, 60, 58, 54, 54,
              58, 50, 52, 54, 48, 69,
              34, 55, 51, 52, 44, 51,
              69, 64, 66, 55, 52, 61,
              46, 31, 57, 52, 44, 18,
              41, 53, 55, 61, 51, 44];

var highScore = 0;
var output;
for (var i = 0; i < scores.length; i++) {
    output = "Bubble solution #" + i + " score: " + scores[i];
    console.log(output);
    if (scores[i] > highScore) {
        highScore = scores[i];
    }
}
console.log("Bubbles tests: " + scores.length);
console.log("Highest bubble score: " + highScore);

var bestSolutions = [];
for (var i = 0; i < scores.length; i++) {
    if (scores[i] == highScore) {
        bestSolutions.push(i);
    }
}
console.log("Solutions with the highest score: " + bestSolutions);

And the winners are...

Bubble solutions #11 and #18 both have a high score of 69! So they are the best bubble solutions in this batch of test solutions.

image with no caption
image with no caption

You’re right, we should be. Given you just learned functions, we wanted to get the basics of arrays out of the way before employing them. That said, you always want to think about which parts of your code you can abstract away into a function. Not only that, but say you wanted to reuse, or let others reuse, all the work that went into writing the bubble computations—you’d want to give other developers a nice set of functions they could work with.

Let’s go back to the Bubble Score code and refactor it into a set of functions. By refactor we mean we’re going to rework how it’s organized, to make it more readable and maintainable, but we’re going to do it without altering what the code does. In other words, when we’re done, the code will do exactly what it does now but it’ll be a lot better organized.

A quick survey of the code...

Let’s get an overview of the code we’ve written and figure out which pieces we want to abstract into functions:

image with no caption
image with no caption

Writing the printAndGetHighScore function

We’ve got the code for the printAndGetHighScore function already. It’s just the code we’ve already written, but to make it a function we need to think through what arguments we’re passing it, and if it returns anything back to us.

Now, passing in the scores array seems like a good idea because that way, we can reuse the function on other arrays with bubble scores. And we want to return the high score that we compute in the function, so the code that calls the function can do interesting things with it (and, after all, we’re going to need it to figure out the best solutions).

Oh, and another thing: often you want your functions to do one thing well. Here we’re doing two things: we’re displaying all the scores in the array and we’re also computing the high score. We might want to consider breaking this into two functions, but given how simple things are right now we’re going to resist the temptation. If we were working in a professional environment we might reconsider and break this into two functions, printScores and getHighScore. But for now, we’ll stick with one function. Let’s get this code refactored:

image with no caption

Refactoring the code using printAndGetHighScore

Now, we need to change the rest of the code to use our new function. To do so, we simply call the new function, and set the variable highScore to the result of the printAndGetHighScore function:

image with no caption

Putting it all together...

Once you’ve completed refactoring your code, make all the changes to “bubbles.html”, just like we have below, and reload the bubble report. You should get exactly the same results as before. But now you know your code is more organized and reusable. Create your own scores array and try some reuse!

image with no caption
image with no caption
image with no caption

So, what’s the job here? It’s to take the leading bubble solutions—that is, the ones with the highest bubble scores—and choose the lowest cost one. Now, luckily, we’ve been given a costs array that mirrors the scores array. That is, the bubble solution score at index 0 in the scores array has the cost at index 0 in the costs array (.25), the bubble solution at index 1 in the scores array has a cost at index 1 in the costs array (.27), and so on. So, for any score you’ll find its cost in the costs array at the same index. Sometimes we call these parallel arrays:

image with no caption
image with no caption

Judy: Well, we know the highest score already.

Frank: Right, but how do we use that? And we have these two arrays, how do we get those to work together?

Judy: I’m pretty sure either of us could write a simple for loop that goes through the scores array again and picks up the items that match the highest score.

Frank: Yeah, I could do that. But then what?

Judy: Anytime we hit a score that matches the highest score, we need to see if its cost is the lowest we’ve seen.

Frank: Oh I see, so we’ll have a variable that keeps track of the index of the “lowest cost high score.” Wow, that’s a mouthful.

Judy: Exactly. And once we get through the entire array, whatever index is in that variable is the index of the item that not only matches the highest score, but has the lowest cost.

Frank: What if two items match in cost?

Judy: Hmm, we have to decide how to handle that. I’d say, whatever one we see first is the winner. Of course we could do something more complex, but let’s stick with that unless the CEO says differently.

Frank: This is complicated enough I think I want to sketch out some pseudocode before writing anything.

Judy: I agree; whenever you are managing indices of multiple arrays things can get tricky. Let’s do that; in the long run I’m sure it will be faster to plan it first.

Frank: Okay, I’ll take a first stab at it...

Get Head First JavaScript Programming now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.