Java 11 Developer Certification - Data Manipulation and Transformation in Array

November 09, 2020

What we are covering in this lesson

  1. Array Data Manipulation methods
  2. Manipulating array using fixed size list
  3. Array Data Transformation methods
  4. List Data Transformation methods
  5. Two Dimensional Arrays

Array Data Manipulation methods

Some of the methods which help in data manipulation in an array are fill, setAll, sort, parallelPrefix, parallelSetAll, parallelSort. All the parallel version of the methods can be used for large set of data, allowing multiple threads to work in parallel. parallelSetAll and parallelSort are operationally the same as setAll and sort, except for they can run multiple threads in parallel.

Lets have a look at these methods using a code example

package maxCode.online.Arrays;

import java.util.Arrays;
import java.util.Collections;

public class ArrayDataManipulation {
	public static void main(String[] args) {
        // Create array of Integer
        Integer[] intArray = new Integer[10];
        System.out.println("Array values initially: " + Arrays.toString(intArray));
 
        // Fill array with a single value
        Arrays.fill(intArray, 5);
        System.out.println("Array values after fill: " + Arrays.toString(intArray));
 
        // You can fill a partial range with Arrays.fill overloaded method
        int partialFillValue = 9;
        Arrays.fill(intArray, 5, 10, partialFillValue);
        System.out.println("Array values after partial fill: " + Arrays.toString(intArray));
 
        // setAll was introduced in Java 8, uses lambda expressions
        Arrays.setAll(intArray, (index) -> index + 1);
        System.out.println("Array values after setAll: " + Arrays.toString(intArray));
 
        // You can sort non primitive data type arrays in reverse this way
        Arrays.sort(intArray, Collections.reverseOrder());
        System.out.println("Array values after reverse sort: " + Arrays.toString(intArray));
 
        // parallelPrefix supports binary operations.
        Arrays.parallelPrefix(intArray, (left, right) -> left + right);
        System.out.println("Array values after parallelPrefix: " + Arrays.toString(intArray));
	}
}

Output

Array values initially: [null, null, null, null, null, null, null, null, null, null]
Array values after fill: [5, 5, 5, 5, 5, 5, 5, 5, 5, 5]
Array values after partial fill: [5, 5, 5, 5, 5, 9, 9, 9, 9, 9]
Array values after setAll: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Array values after reverse sort: [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
Array values after parallelPrefix: [10, 19, 27, 34, 40, 45, 49, 52, 54, 55]

We are first creating an array of Integers, and populating it with a single value using Arrays.fill. Then we are again using it for partial fill. setAll was introduced in Java 8 and uses lambda expression, to set the values for each element in array. Sorting in reverseOrder using Collections.reverseOrder works only on non-primitive data. And then we have the parallel version implementation.

Manipulating array using fixed size list

There are two methods List.of and List.copyOf which we will demonstrate below. The most important thing about these methods is that these methods is that they return an immutable list, meaning we cannot change the list. List.of takes an array and makes it a list. List.copyOf takes a list and makes another list. The below code demonstrates the methods on the list interface which can be applied on arrays.

package maxCode.online.Arrays;

import java.util.Arrays;
import java.util.List;

public class ListDataManipulation {
	public static void main(String[] args) {
		// Set up some test data for use in our tests
		String[] primaryColors = { "red", "blue", "yellow" };
		String[] secondaryColors = { "green", "orange", "purple" };

		System.out.println("--- Manipulating array data using a List");

		// The Arrays.asList returns a list backed by the array;
		List<String> colorList = Arrays.asList(primaryColors);
		System.out.println("colorList: " + colorList.toString());

		// Use get method to get an element in the array
		String firstColor = colorList.get(0);
		System.out.println("firstColor is " + firstColor);

		// Sort the array via the List reference
		colorList.sort(String.CASE_INSENSITIVE_ORDER);
		System.out.println("\ncolorList after sort: " + colorList.toString());
		System.out.println("primaryColors " + Arrays.toString(primaryColors));

		// Set the value of an array element using set method
		colorList.set(0, "cyan");
		System.out.println("\ncolorList after after changing 1st value : " + colorList.toString());
		System.out.println("primaryColors " + Arrays.toString(primaryColors));

		// Use replaceAll method to change all values in the array via
		// List reference
		colorList.replaceAll((s) -> s + "ish");
		System.out.println("\ncolorList  after replacing all values: " + colorList.toString());
		System.out.println("primaryColors " + Arrays.toString(primaryColors));

		// And what happens when we change underlying array?
		primaryColors[0] = "blueish";
		System.out.println("\ncolorList after array changed: " + colorList.toString());
		System.out.println("primaryColors " + Arrays.toString(primaryColors));
		System.out.println("\n--- List.of and List.copyOf Examples");

		// List.of method can take an array and make it a list
		List secondColorList = List.of(primaryColors);

		// List.copyOf method takes a list and makes another list
		List thirdColorList = List.copyOf(Arrays.asList(primaryColors));

		System.out.println("\nsecondColorList : " + secondColorList.toString());
		System.out.println("thirdColorList : " + thirdColorList.toString());

		// Change value on original array
		primaryColors[0] = "blue";

		System.out.println("\nprimaryColors after making first element blue: " + Arrays.toString(primaryColors));
		System.out.println("secondColorList after array changed : " + secondColorList.toString());
		System.out.println("thirdColorList after array changed : " + thirdColorList.toString());

        // Below code, if uncommented, will throw UnsupportedOperationException (Runtime Exception)
		// secondColorList created from List.of method is immutable
		/*try {
			secondColorList.set(0, "cyan");
		} catch (Exception e) {
			e.printStackTrace();
		}

		// thirdColorList created from List.copyOf method is also immutable
		try {
			thirdColorList.set(0, "cyan");
		} catch (Exception e) {
			e.printStackTrace();
		}*/
	}
}

Output

--- Manipulating array data using a List
colorList: [red, blue, yellow]
firstColor is red

colorList after sort: [blue, red, yellow]
primaryColors [blue, red, yellow]

colorList after after changing 1st value : [cyan, red, yellow]
primaryColors [cyan, red, yellow]

colorList  after replacing all values: [cyanish, redish, yellowish]
primaryColors [cyanish, redish, yellowish]

colorList after array changed: [blueish, redish, yellowish]
primaryColors [blueish, redish, yellowish]

--- List.of and List.copyOf Examples

secondColorList : [blueish, redish, yellowish]
thirdColorList : [blueish, redish, yellowish]

primaryColors after making first element blue: [blue, redish, yellowish]
secondColorList after array changed : [blue, redish, yellowish]
thirdColorList after array changed : [blue, redish, yellowish]

The last commented part will throw Runtime Exception if uncommented, since the lists returned by List.of and List.copyOf are immutable copies of the underlying data.

Array Data Transformation methods

The data transformation methods transform the array list into another type of data. We use Arrays.copyOf and Arrays.copyOfRange methods to achieve this. Different ways to use these method are demonstrated below.

package maxCode.online.Arrays;

import java.util.Arrays;

public class ArrayTransformation {
	public static void main(String[] args) {
		System.out.println("-----------Using Arrays.copyOf ----------");

		// Create an array of Integer
		Integer[] originalArray = new Integer[10];

		// Initialize values to 1 - 10
		Arrays.setAll(originalArray, (index) -> index + 1);
		System.out.println("integerArray values = " + Arrays.toString(originalArray));

		// Create Copy of array, same size
		Integer[] copiedArray = Arrays.copyOf(originalArray, originalArray.length);

		System.out.println("copiedArray values = " + Arrays.toString(copiedArray));

		// Create Copy of of an array, trimmed to specified size
		Integer[] trimmedArray = Arrays.copyOf(originalArray, 7);

		// Copy array to larger array, extra elements get default values
		Integer[] widenedArray = Arrays.copyOf(originalArray, 15);

		System.out.println("trimmedArray values = " + Arrays.toString(trimmedArray));
		System.out.println("widenedArray values = " + Arrays.toString(widenedArray));

		// Create Copy of defined portion of Array
		Integer[] croppedArray = Arrays.copyOfRange(originalArray, 2, 6);
		System.out.println("croppedArray values = " + Arrays.toString(croppedArray));

		croppedArray[0] = 5;
		System.out.println("croppedArray values after a change = " + Arrays.toString(croppedArray));
	}
}

Output

-----------Using Arrays.copyOf ----------
integerArray values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
copiedArray values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
trimmedArray values = [1, 2, 3, 4, 5, 6, 7]
widenedArray values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, null, null, null, null, null]
croppedArray values = [3, 4, 5, 6]
croppedArray values after a change = [5, 4, 5, 6]

List Data Transformation methods

We will look at subList and toArray method here. subList creates a list from a smaller set of elements. toArray transforms a list to an array. The below code shows the usage of these methods

package maxCode.online.Arrays;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

public class ListTransformation {
	public static void main(String[] args) {
		// Create a new Integer array
        Integer[] integerArray = new Integer[10];

        // Set values to 1 - 10
        Arrays.setAll(integerArray, (index) -> index + 1);

        System.out.println("integerArray values = " +
                Arrays.toString(integerArray));

        List anotherList = List.of(integerArray);

        // Create a subList of a list
        List shortList = anotherList.subList(3, 7);
        System.out.println("shortList values : " + shortList.toString());

        // And now go from list to array...
        Integer[] repeatedArray = new Integer[10];
        anotherList.toArray(repeatedArray);
        System.out.println("array created from toArray method : " +
                Arrays.toString(repeatedArray));

        System.out.println("------  iterator tests --------");
        // Iterator allows forward processing of list elements
        System.out.println("loop through anotherList.iterator() values...");
        for (Iterator it = anotherList.iterator(); it.hasNext(); ) {
            System.out.print(it.next());
        }

        // ListIterator allows backwards and forwards processing
        // of list elements
        System.out.println("\nloop through anotherList.listIterator() values...");
        ListIterator lit = anotherList.listIterator();

        for (int i = 0; lit.hasNext(); i++) {
            System.out.print(lit.next());
            if (i == 4) {
                System.out.println("\nreverse direction");
                for (; lit.hasPrevious(); ) {
                    System.out.print(lit.previous());
                }
                break;
            }
        }
	}
}

Output:

integerArray values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
shortList values : [4, 5, 6, 7]
array created from toArray method : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
------  iterator tests --------
loop through anotherList.iterator() values...
12345678910
loop through anotherList.listIterator() values...
12345
reverse direction
54321

We have created a new Integer array, set the values, create another list using List.of, then creating a subList from that list and then converting an array to List using List.toArray. The iterator used after that allows only forward processing of the list elements. The ListIterator on the other hand allows backward as well as forward processing of the elements.

We’ve seen here that the java.lang.Arrays utility class provides many of the methods you would need to manipulate data in an array. And additionally, you can use some of the list methods, to directly access your array, if you use the Arrays.asList transformation method. The alternative to the array is an ArrayList, which is a collection of data that is resizeable and implements the interfaces List and Collection, to name a couple.

Two Dimensional Arrays

A two dimensional array in java is an array which is referencing other array objects. Below code creates a two dimensional int array, and also we can see various uses of the two dimensional array. You can clone a two dimensional array using the clone method but it only clones the first dimension’s array reference, and so it also called shallow copy. We can iterate through the array and copy it manually for a deep copy. All this is demonstrated in the below code.

package maxCode.online.Arrays;

import java.util.Arrays;

public class TwoDimensionalArray {
	public static void printArray(String arrayName, int[][] inputArray) {
		System.out.println("------------------------------------------");
		System.out.println(arrayName + " Reference: " + inputArray);
		for (int row = 0; row < inputArray.length; row++) {
			printRow(arrayName, inputArray[row], row);
		}
	}

	public static void printRow(String arrayName, int[] inputArray, int row) {
		System.out.println(arrayName + " : " + inputArray + " : Row " + (row + 1) + " :  " 
				+ Arrays.toString(inputArray));
	}

	public static void main(String[] args) {
		// Create a 2-d array
		int[][] intArray = new int[2][10];

		// Let's see what this looks like using the method we created
		printArray("intArray", intArray);

		// You can also print the 2-d array Using Arrays.deepToString()
		System.out.println("Printing a multi-dimensional array using " + "Arrays.deepToString()");
		System.out.println(Arrays.deepToString(intArray));

		int[][] variableCols = { { 1, 2, 3 }, { 5, 6, 7, 8 }, { 0, 3, 4, 6 }, { 1 } };
		printArray("variableCols", variableCols);

		// Clone a copy of your 2-d array, but it is a shallow clone.
		int[][] clonedArray = variableCols.clone();
		printArray("Shallow copy - clonedArray", (int[][]) clonedArray);

		// Arrays.copyOf works here, but need to cast back to 2-d array
		int[][] copiedCopy = (int[][]) Arrays.copyOf(variableCols, variableCols.length);
		printArray("copiedCopy", copiedCopy);

		System.out.println("-------------------------------------------");
		// Comparing our arrays, row 3....
		printRow("variableCols", variableCols[2], 2);
		printRow("copiedCopy", ((int[][]) copiedCopy)[2], 2);
		printRow("clonedArray", ((int[][]) clonedArray)[2], 2);

		System.out.println("-------------------------------------------");
		// We can take our shallow copy and make it 'deep' manually.
		System.out.println("-----Deep Copy-----");
		for (int i = 0; i < clonedArray.length; i++) {
			clonedArray[i] = clonedArray[i].clone(); // clone each element
		}
		// Change data on one of our original data points.
		variableCols[2][3] = 10000;

		// Comparing our arrays, row 3....
		printRow("variableCols", variableCols[2], 2);
		printRow("clonedArray", clonedArray[2], 2);
		System.out.println("-------------------------------------------");
	}
}

Output

------------------------------------------
intArray Reference: [[I@73a8dfcc
intArray : [I@ea30797 : Row 1 :  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
intArray : [I@7e774085 : Row 2 :  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Printing a multi-dimensional array using Arrays.deepToString()
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
------------------------------------------
variableCols Reference: [[I@3f8f9dd6
variableCols : [I@aec6354 : Row 1 :  [1, 2, 3]
variableCols : [I@1c655221 : Row 2 :  [5, 6, 7, 8]
variableCols : [I@58d25a40 : Row 3 :  [0, 3, 4, 6]
variableCols : [I@1b701da1 : Row 4 :  [1]
------------------------------------------
Shallow copy - clonedArray Reference: [[I@726f3b58
Shallow copy - clonedArray : [I@aec6354 : Row 1 :  [1, 2, 3]
Shallow copy - clonedArray : [I@1c655221 : Row 2 :  [5, 6, 7, 8]
Shallow copy - clonedArray : [I@58d25a40 : Row 3 :  [0, 3, 4, 6]
Shallow copy - clonedArray : [I@1b701da1 : Row 4 :  [1]
------------------------------------------
copiedCopy Reference: [[I@442d9b6e
copiedCopy : [I@aec6354 : Row 1 :  [1, 2, 3]
copiedCopy : [I@1c655221 : Row 2 :  [5, 6, 7, 8]
copiedCopy : [I@58d25a40 : Row 3 :  [0, 3, 4, 6]
copiedCopy : [I@1b701da1 : Row 4 :  [1]
-------------------------------------------
variableCols : [I@58d25a40 : Row 3 :  [0, 3, 4, 6]
copiedCopy : [I@58d25a40 : Row 3 :  [0, 3, 4, 6]
clonedArray : [I@58d25a40 : Row 3 :  [0, 3, 4, 6]
-------------------------------------------
-----Deep Copy-----
variableCols : [I@58d25a40 : Row 3 :  [0, 3, 4, 10000]
clonedArray : [I@ee7d9f1 : Row 3 :  [0, 3, 4, 6]
-------------------------------------------