Concepts / Array processing with loops

Array processing with loops

Arrays.fill sets every element, or a range of elements, to one value. In the range form the starting index is included and the ending index is excluded.

  • Programming

Whole-Collection Tasks in Practice

Once a program stores its data in an array, it often needs to do something to the whole collection at once. It may need to reset every slot, display the contents in a readable form, put the values in order, or check whether a particular value is present. Writing a loop by hand for each of these tasks is possible, but the Arrays class provides ready-made methods for them. This article follows four of those methods, which handle filling, text conversion, sorting, and searching.

The Arrays class has several versions of each method, with one version for each kind of array element type. The ideas stay the same from version to version, so learning the behavior of one version gives you most of what you need for the others. The examples below use int arrays, but the same reasoning applies to other element types.

What do you think happens?

You create int[] arr = new int[6]; (all six cells hold 0) and then call Arrays.fill(arr, 2, 5, 9). What is the value at index 5?

  • 9, because index 5 is inside the fill

  • 0, because the ending index is excluded

  • 9, because the fill always reaches the last cell

Reveal answer
Answer:

0, because the ending index is excluded

The range form fills indexes 2, 3, and 4. The ending index 5 is not included, so that cell keeps its original value of 0.

Filling Every Cell with One Value

Arrays.fill is the method you reach for when every cell needs the same value, or when a stretch of cells needs to be reset. It comes in two forms. The first form takes an array and a value, and fills the entire array with that value. The second form takes an array, a starting index, an ending index, and a value, and fills only the cells in that range.

java
Output
[0, 7, 7, 7, 0, 0]
Notes on the code
  • new int[6] creates six cells, each starting at 0
  • The range form starts at index 1 and stops before index 4
  • Arrays.toString is used only to display the result

The whole-array form of fill has no index arguments. Calling Arrays.fill(scores, 3) would set every one of the six cells to 3. Use the whole-array form when the entire collection should be reset, and the range form when only part of it should change.

Reading the Half-Open Range

The range form deserves a careful reading. The starting index is included in the fill, but the ending index is not. The last cell that receives the value is the one just before the ending index. Many learners assume the range is closed on both ends, so this half-open style is worth committing to memory now. It matches the way Java ranges are described throughout the language.

index 00index 17index 27index 37index 40index 50
Which exact positions change when Arrays.fill(arr, from, to, value) runs, and why is the element at index 'to' left untouched? Here from is 1 and to is 4, so indexes 1, 2, and 3 receive 7 while index 4 keeps its original 0.
Worked example

Tracing a range fill step by step

Start with int[] arr = new int[6]; so every cell is 0. Then run Arrays.fill(arr, 1, 4, 7). Which cells change, and what does the array look like afterward?

  1. 1
    Identify the start

    The starting index is 1, so index 1 is the first cell that receives the value 7.

  2. 2
    Identify the end

    The ending index is 4. It is excluded, so the last cell filled is index 3.

  3. 3
    Apply the fill

    Indexes 1, 2, and 3 are set to 7. Index 0 and indexes 4 and 5 are not part of the range, so they keep their value of 0.

  4. 4
    Check the count

    The number of cells filled is the ending index minus the starting index, which is 4 minus 1, or 3 cells.

Result

The array becomes [0, 7, 7, 7, 0, 0].

Converting an Array to Readable Text

Arrays.toString takes an array and returns a String that describes its contents. The String lists every value, separates the values with commas, and wraps the whole list in square brackets. Each value is converted to text in the same way it would appear if you printed it, so you do not need to write a loop that builds the text yourself.

java
Output
[21, 19, 24]
Notes on the code
  • The method returns a String, which can be printed or stored in a variable
  • Commas separate the values and square brackets surround the list

Sorting an Array In Place

Arrays.sort rearranges the values in an array so that they end up in increasing order. The change happens in place, which means the same array object is altered rather than a new sorted copy being returned. Like the fill methods, sort has a whole-array form and a range form. The whole-array form sorts every element. The range form sorts only the elements from the starting index up to, but not including, the ending index. The same exclusive-end rule applies here as it did for fill.

Before
int[] nums = {5, 2, 8, 1, 9};

Index 0 holds 5, index 1 holds 2, index 2 holds 8, index 3 holds 1, index 4 holds 9

After
Arrays.sort(nums);
// nums now holds [1, 2, 5, 8, 9]

Index 0 holds 1, index 1 holds 2, index 2 holds 5, index 3 holds 8, index 4 holds 9

5index 01index 02index 12index 18index 25index 21index 38index 39index 49index 4
What does the array look like before and after Arrays.sort(nums), and which values moved to new positions? Indexes 0, 2, and 3 changed value; indexes 1 and 4 already held the value they end with.
java
Output
[5, 1, 2, 8, 9]
Notes on the code
  • The range 1 to 4 covers indexes 1, 2, and 3, holding 2, 8, and 1
  • Those three values are sorted into 1, 2, 8
  • Index 0 (value 5) and index 4 (value 9) are outside the range and stay in place

What Can Be Sorted

Sorting works on arrays of String values and arrays of the primitive types, with one exception: boolean arrays are not supported. Sorting also has a requirement that is easy to overlook. The method must be able to decide which of any two values is smaller. An array whose values cannot be compared in that way cannot be sorted by this method. The sorting algorithms themselves are covered later in the course, in the chapter that discusses algorithms.

Searching a Sorted Array with binarySearch

Arrays.binarySearch looks for a particular value in an array and reports where it is. It returns an int. If the value is present, the return value is the index of an element that holds it. The method has one firm requirement: the array must already be sorted in increasing order before you call it. The sort step and the search step therefore belong together. Sorting first is what makes the search meaningful. If you search an array that is not sorted, the method's description does not promise a useful answer, so you should not rely on the result.

java
Output
3
-4
Notes on the code
  • The value 8 is present at index 3, so the return value is that index
  • The value 6 is absent, so the method returns a negative number
  • The -4 is explained in the next section
index 01-4return value for key 6index 12index 25index 38index 49insertion point 3
If the key is missing, how do I convert the negative return value -(insertionPoint) - 1 back into the position where the key would be inserted? Searching for 6 in the sorted array gives an insertion point of 3, because 6 would sit between 5 at index 2 and 8 at index 3. The return value is -(3) - 1, which is -4.

Interpreting Negative Return Values

The source describes the absent-value case as returning -1. Java's documented behavior is more precise: when the key is missing, the method returns -(insertion point) - 1, where the insertion point is the index at which the key would be placed to keep the array sorted. The -1 result from the source is what you get when the insertion point is 0, meaning the key is smaller than every element. For any other missing key, the return value is more negative than -1.

Formula, step by step
return value = -(insertionPoint) - 1
  1. 1
    Find the insertion point: the index where the missing key would go to keep the array sorted
  2. 2
    Negate it and subtract 1, so the result is always negative for a missing key
  3. 3
    To recover the insertion point from a negative result r, compute -r - 1
  4. 4
    Example: for the value 6 in {1, 2, 5, 8, 9}, the insertion point is 3, the return value is -4, and -(-4) - 1 gives back 3

Mistakes Beginners Make

  • Common mistake

    Assuming the fill range includes the ending index

    What it looks like
    Arrays.fill(arr, 1, 4, 7) is expected to change index 4
    Why it fails

    The starting index is included and the ending index is excluded, so the last filled cell is index 3.

    Do this instead

    Count the filled cells as the ending index minus the starting index.

  • Common mistake

    Expecting Arrays.sort to return a new array

    What it looks like
    int[] sorted = Arrays.sort(nums); with the intention of keeping nums unchanged
    Why it fails

    Sorting happens in place, so the original array is rearranged.

    Do this instead

    Call Arrays.sort(nums) and then use nums, or make a copy first if the original order must be kept.

  • Common mistake

    Calling binarySearch on an unsorted array

    What it looks like

    Searching {5, 2, 8, 1, 9} for 8 without sorting it first

    Why it fails

    The method requires the array to be sorted in increasing order, and the description does not promise a useful answer otherwise.

    Do this instead

    Sort the array first, then search it.

  • Common mistake

    Using a negative search result as an index

    What it looks like
    arr[Arrays.binarySearch(arr, 6)] when the key 6 is missing
    Why it fails

    The result is negative for a missing key, so it is not a valid index for the array.

    Do this instead

    Check whether the result is negative first, then convert it with -(result) - 1 if you need the insertion point.

  • Common mistake

    Sorting a boolean array, which Arrays.sort does not support

Predict, Then Trace a Pipeline

These four methods are often used together. A common pattern is to fill or populate an array, sort it so the values are in order, search it with binarySearch, and print the contents with toString. When you read a program, identify which of these steps each call performs. That habit makes the flow of the program much easier to follow.

MEDIUM

Start with int[] a = {4, 9, 1, 7}; Before running any code, predict the contents of a after Arrays.sort(a), then predict the return value of Arrays.binarySearch(a, 7) on the sorted array. Then predict the output of Arrays.toString(a) afterward, and check your answers by running the code.

Hints
  • Sorting rearranges the values into increasing order, in place.
  • Count the sorted positions starting at index 0 and find where 7 lands.
  • The expected sorted contents are [1, 4, 7, 9].

Key Takeaways

  • Arrays.fill sets every element or a range of elements to one value; in the range form the starting index is included and the ending index is excluded.
  • Arrays.toString returns a String listing the values separated by commas inside square brackets, without requiring a hand-written loop.
  • Arrays.sort rearranges values into increasing order in place, with a range form that uses the same exclusive-end rule; boolean arrays are not supported.
  • Arrays.binarySearch requires a sorted array, returns the index of a found value, and returns a negative value for a missing key, which converts back to an insertion point via -(result) - 1.