106. Filling and setting an array

Sometimes, we need to fill up an array with a fixed value. For example, we may want to fill up an array of integers with the value 1. The simplest way to accomplish this relies on a for statement as follows:

int[] arr = new int[10];

// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
for (int i = 0; i < arr.length; i++) {
arr[i] = 1;
}

But we can reduce this code to a single line of code by means of the Arrays.fill() methods. This method comes in different flavors for primitives and for objects. The preceding code can be rewritten via Arrays.fill(int[] a, int val) as follows:

// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
Arrays.fill(arr, 1);
Arrays.fill() also come with flavors for filling up just a segment/range of an array. For integers, this method is fill​(int[] a, int fromIndexInclusive, int toIndexExclusive, int val).

Now, how about applying a generator function to compute each element of the array? For example, let's assume that we want to compute each element as the previous one plus 1. The simplest approach will again rely on a for statement as follows:

// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
for (int i = 1; i < arr.length; i++) {
arr[i] = arr[i - 1] + 1;
}

The preceding code has to be modified accordingly depending on the computations that need to be applied to each element.

For such tasks, JDK 8 comes with a bunch of Arrays.setAll() and Arrays.parallelSetAll() methods. For example, the preceding snippet of code can be rewritten via setAll​(int[] array, IntUnaryOperator generator) as follows:

// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
Arrays.setAll(arr, t -> {
if (t == 0) {
return arr[t];
} else {
return arr[t - 1] + 1;
}
});
Besides this method, we also have setAll​(double[] array, IntToDoubleFunction generator), setAll​(long[] array, IntToLongFunction generator), and setAll​(T[] array, IntFunction<? extends T> generator).

Depending on the generator function, this task can be accomplished in parallel or not. For example, the preceding generator function cannot be applied in parallel since each element depends on the value of the preceding element. Trying to apply this generator function in parallel will lead to incorrect and unstable results.

But let's assume that we want to take the preceding array (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) and multiply each even value by itself and decrease each odd value by 1. Since each element can be computed individually, we can empower a parallel process in this case. This is the perfect job for Arrays.parallelSetAll() methods. Basically, these methods are meant to parallelize  Arrays.setAll() methods.

Let's now apply parallelSetAll​(int[] array, IntUnaryOperator generator) to this array:

// 0, 4, 2, 16, 4, 36, 6, 64, 8, 100
Arrays.parallelSetAll(arr, t -> {
if (arr[t] % 2 == 0) {
return arr[t] * arr[t];
} else {
return arr[t] - 1;
}
});
For each Arrays.setAll() method, there is an Arrays.parallelSetAll() method.

As a bonus, Arrays come with a set of methods named parallelPrefix(). These methods are useful for applying a mathematical function to the elements of the array, both cumulatively and concurrently.

For example, if we want to compute each element of the array as the sum of the preceding elements, then we can do it as follows:

// 0, 4, 6, 22, 26, 62, 68, 132, 140, 240
Arrays.parallelPrefix(arr, (t, q) -> t + q);
..................Content has been hidden....................

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