• 8.1: Declaring + Initializing 2D Arrays; Determining their
    • Declaring a 2D array
  • Initializing a 2D array
  • Size of 2D Arrays
  • Accessing the Elements of a 2D Array
  • Notes on Common Mistakes
  • Hacks
  • 8.1: Declaring + Initializing 2D Arrays; Determining their

    Review: Arrays are a collection (list) of elements (primitive or object reference type data)

    So, a 2-Dimensional array is an array where the elements within that array are other arrays

    2D arrays can be better at storing certain types of information

    • Especially if the data represents a space, with rows and columns

    Seating chart:

    . Column 1 Column 2 Column 3  
    Row 1 Abby Ben Clara Principalida
    Row 2 Ethan Frank   Flanklin
    Row 3 Isabelle John Kim Leo

    Note that this is a non-rectangular 2D array

    • Or if the data needs to be classified under categories
    . Month 1 Month 2 Month 3
    Winter December January February
    Spring March April May
    Summer June July August
    Fall Summer October November

    This is a rectangular 2D array. Non-rectangular 2D arrays are not a part of the CSA course

    Declaring a 2D array

    2D Arrays can be declared like this:

    dataType[][] nameOfArray;

    Initializing a 2D array

    new dataType[r][c];

    r: number of rows (number of arrays)
    c: number of columns (length of each array)

    public class Seasons {
    
        private String[][] Seasons = new String[2][3];
    
        // Or, if you already know what the elements should be:
    
        private String[][] Seasons2 = {
            {"December", "January", "February"},
            {"March", "April", "May"},
            {"June", "July", "August"},
            {"September", "October", "November"}
        };
    
    }
    
    

    Size of 2D Arrays

    The size of the 2D array is classified by number of rows by number of columns

    Number of rows can be found like this:

    r = trimesterCourses.length

    This would give the number of arrays within the 2D array, since each array is an element

    For number of columns:

    c = trimesterCourses[0].length

    This finds the number of elements of the first array within the 2D array.

    Accessing the Elements of a 2D Array

    The elements of a 2D array can be accessed using index

    Seasons[0][2]

    Output: February

    the value in the first bracket is the index of the rows, or which array we are accessing. In this case, the 0th index means we are accessing the first array

    The value in the second bracket is the index within the array. So we are looking for the 2nd value within the first array.

    To update the element of a 2D array, all you need to do is reference its location and change the value.

    public class Seasons {
    
        private String[][] seasons = new String[2][3];
    
        private static String[][] seasons2 = {
            {"December", "January", "February"},
            {"March", "April", "May"},
            {"June", "July", "August"},
            {"September", "October", "November"}
        };
    
        public static void main(String[] args) {
            System.out.println(seasons2[0][2]);
            seasons2[0][2] = "Changed Value";  
            System.out.println(seasons2[0][2]);
        }
    }
    
    Seasons.main(null);
    
    
    

    Notes on Common Mistakes

    Here are some notes on common mistakes made in the context of the 2D arrays question. People around the country will definitely make all of these mistakes many times over, so let’s hope that none of those people are people at our school.

    Array Errors

    We just had a lesson on common Arrays errors, so rather than rephrase their work, give these mistakes another look.

    There are some Array errors that are especially relevant to 2D arrays problems, however. For example…

    • Off-By-One Errors

    When working with a 2D array, you are working with an array full of arrays. In this structure, there is a set number of rows and columns when the structure is initialized. The length of each row and the number of rows are often different, so both must be identified properly before iterating using index-based loops.

    Out of bounds errors will always lose you at least one point on the scoring guidelines, according to our research.

    • For-Each loop modification

    If values are intended to be modified during an iterative process, do not use a for-each loop. The elements accessed using this strategy are copies; accessing the array indexes directly to make modifications is the only way for them to be retained. See the example below:

    import java.util.Arrays;
    
    int[][] modifyArray = {
        {1, 4, 3},
        {3, 8, 9}
    };
    
    System.out.println("Prior to modification: " + Arrays.deepToString(modifyArray));
    
    for (int[] row : modifyArray) {
        for (int col : row) {
            if (col == 3) {
                col = 0;
            }
        }
    }
    
    System.out.println("After to modification: " + Arrays.deepToString(modifyArray));
    
    Prior to modification: [[1, 4, 3], [3, 8, 9]]
    After to modification: [[1, 4, 3], [3, 8, 9]]
    

    Instead, when modifying, you can use a traditional for loop (which also comes with the added benefit of having direct access to the relevant indexes):

    import java.util.Arrays;
    
    int[][] actualModifyArray = {
        {1, 4, 3},
        {3, 8, 9}
    };
    
    System.out.println("Prior to modification: " + Arrays.deepToString(actualModifyArray));
    
    for (int r = 0; r < actualModifyArray.length; r++) {
        for (int c = 0; c < actualModifyArray[r].length; c++) {
            if (actualModifyArray[r][c] == 3) {
                actualModifyArray[r][c] = 0;
            }
        }
    }
    
    System.out.println("After to modification: " + Arrays.deepToString(actualModifyArray));
    
    Prior to modification: [[1, 4, 3], [3, 8, 9]]
    After to modification: [[1, 4, 0], [0, 8, 9]]
    

    FRQ Scoring Guidelines Mistakes

    To succeed on the AP test, it’s important to be able to identify which elements of a correct answer earn points.

    • Most often, if you create a method in a previous part used to interact with a 2D array, it is intended that you use that method again in future methods.

    Means of traversing and interacting with 2D arrays are relatively specific in the context of one College Board problem (i.e., iterate through to determine a condition about a row, find a value in a row, search columns by condition, etc.), so make sure to analyze the context to determine if a certain method may be used again to abstract what would otherwise be a more complex task in a future method. With practice, this connection should be obvious.

    If there is no possible relevance between two methods, this may not necessarily be the case.

    Make sure that you use the proper parameters when calling your own method! Scoring guidelines are sometimes lenient about this, but don’t tempt fate. Just format your call properly.

    • If a “helper” method is provided to you in a question, make sure to note it and use it.

    If one is provided, it is most certainly present to make the process of writing the code less complex. Scoring guidelines will always include utilizing past student-created methods and “helper” methods.

    You can also use the helper method’s functionality to aid your thinking about a question. If you are confused by its content and aren’t sure how to tackle the problem instinctively, you can be sure that a provided “helper” method will be a part of the solution.

    Once again, make sure that you’re using the proper parameters!

    • Know how to use column-major order. (Many go into the test having only used row-major order.)

    It’s very possible that a question will prompt you to access a 2D array by its columns. (We found two in research for this lesson.) If you know you haven’t practiced column-major order, give the code below a look. It might be a good idea to create your own code cell with a unique 2D array to practice with.

    int[][] array = {
        {3, 5, 1},
        {9, 9, 7}
    };
    
    // you should always be able to use array[0].length for the number of columns
    // since each row is the same length
    int colNum = 1;
    for (int col = 0; col < array[0].length; col++) {
        System.out.print("Column " + colNum + ":\t");
        for (int row = 0; row < array.length; row++) {
            System.out.print(array[row][col] + "\t");
        }
        System.out.println();
        colNum++;
    }
    
    Column 1:	3	9	
    Column 2:	5	9	
    Column 3:	1	7	
    

    Popcorn Hack:

    public class TrimesterGrades {
    
        private int[][] trimesterGrades = {
            {85, 90, 78, 92, 99}, // tri 1
            {92, 88, 91, 97, 80}, // tri 2
            {79, 85, 83, 95, 67}  // tri 3
        };
    
    }
    

    The 2D array keeps track of a students grade, grouped by each trimester. The student, currently in Trimester 3, retook a test in their 3rd period, which raised that grade to 90.

    Show how they would write code that changes the grade for the 3rd period class

    Answer

    I did that below with a custom method.

    public class TrimesterGrades {
        private int[][] trimesterGrades = {
            {85, 90, 78, 92, 99}, // tri 1
            {92, 88, 91, 97, 80}, // tri 2
            {79, 85, 83, 95, 67}  // tri 3
        };
    
        private void changeGrade(int trimester, int period, int newGrade) {
            try {
                trimesterGrades[trimester - 1][period - 1] = newGrade;
            } catch (ArrayIndexOutOfBoundsException e) {
                System.out.println("The grade could not be changed due to invalid arguments:\n" + e.getMessage());
            }
        }
    
        public static void main(String[] args) {
            TrimesterGrades example = new TrimesterGrades();
            // showing error handler
            System.out.println("Improperly attempting to change the grade (using wrong indexes):");
            example.changeGrade(4, 1, 97);
            // changing the grade properly
            System.out.println("\nNow, the student's grade is properly changed to 90:");
            System.out.println("\tBefore change: " + Arrays.deepToString(example.trimesterGrades));
            example.changeGrade(3, 3, 90); // here's the good call
            System.out.println("\tAfter change: " + Arrays.deepToString(example.trimesterGrades));
        }
    }
    
    TrimesterGrades.main(null);
    
    Improperly attempting to change the grade (using wrong indexes):
    The grade could not be changed due to invalid arguments:
    Index 3 out of bounds for length 3
    
    Now, the student's grade is properly changed to 90:
    	Before change: [[85, 90, 78, 92, 99], [92, 88, 91, 97, 80], [79, 85, 83, 95, 67]]
    	After change: [[85, 90, 78, 92, 99], [92, 88, 91, 97, 80], [79, 85, 90, 95, 67]]
    

    Hacks

    Check out parts (b), (c), and full working code below.

    Part (b)

    Write a static method rowSums that calculates the sums of each of the rows in a given twodimensional array and returns these sums in a one-dimensional array. The method has one parameter, a twodimensional array arr2D of int values. The array is in row-major order: arr2D[r][c] is the entry at row r and column c. The method returns a one-dimensional array with one entry for each row of arr2D such that each entry is the sum of the corresponding row in arr2D. As a reminder, each row of a two-dimensional array is a one-dimensional array. For example, if mat1 is the array represented by the following table, the call rowSums(mat1) returns the array {16, 32, 28, 20}. Assume that arraySum works as specified, regardless of what you wrote in part (a). You must use arraySum appropriately to receive full credit. Complete method rowSums below.

    /** Returns a one-dimensional array in which the entry at index k is the sum of * the entries of row k of the two-dimensional array arr2D. */ 
    public static int[] rowSums(int[][] arr2D) {
        int[] output = new int[arr2D.length]; // initializing with the length equal to the number of 2d arr rows
        for (int i = 0; i < arr2D.length; i++) {
            output[i] = arraySum(arr2D[i]); // each element is the sum of one of the 2d rows, in order
        }
        return output;
    }
    

    Part (c)

    A two-dimensional array is diverse if no two of its rows have entries that sum to the same value. In the following examples, the array mat1 is diverse because each row sum is different, but the array mat2 is not diverse because the first and last rows have the same sum.Assume that arraySum and rowSums work as specified, regardless of what you wrote in parts (a) and (b). You must use rowSums appropriately to receive full credit. Complete method isDiverse below.

    /** Returns true if all rows in arr2D have different row sums; * false otherwise. */ 
    public static boolean isDiverse(int[][] arr2D) {
        int[] arr2DSums = rowSums(arr2D);
        for (int i = 0; i < arr2DSums.length; i++) {
            for (int j = 0; j < i; j++) { // checking if the current element is equal to any previous element
                if (arr2DSums[i] == arr2DSums[j]) {
                    return false; // false if a dupe is found
                }
            }
        }
        return true; // true if no dupes are found
    }
    

    Full Working Code

    See a full working block of code below that runs properly, including a tester method:

    public class DiverseArray {
        // Method from (a): returns the sum of the entries in the one-dimensional array arr.
        public static int arraySum(int[] arr) {
            int sum = 0;
            for (int i : arr) sum += i;
            return sum;
        }
    
        // Method from (b): returns a one-dimensional array in which the entry at index k is the sum of the entries of row k of the two-dimensional array arr2D.
        public static int[] rowSums(int[][] arr2D) {
            int[] output = new int[arr2D.length];
            for (int i = 0; i < arr2D.length; i++) {
                output[i] = arraySum(arr2D[i]);
            }
            return output;
        }
    
        // Method from (c): returns true if all rows in arr2D have different row sums; false otherwise.
        public static boolean isDiverse(int[][] arr2D) {
            int[] arr2DSums = rowSums(arr2D);
            for (int i = 0; i < arr2DSums.length; i++) {
                for (int j = 0; j < i; j++) { // checking if the current element is equal to any previous element
                    if (arr2DSums[i] == arr2DSums[j]) {
                        return false; // false if a dupe is found
                    }
                }
            }
            return true; // true if no dupes are found
        }
        
        // main method used to verify the functionality of each method
        public static void main(String[] args) {
            // PART (a)
            System.out.println("PART (a)");
            int[] sumOf7 = {1, 2, 4}; // sum: 7
            int[] sumOf19 = {11, 3, 5}; // sum: 19
            System.out.println("arraySum test: array with a sum of 7 returns: " + arraySum(sumOf7));
            System.out.println("arraySum test: array with a sum of 19 returns: " + arraySum(sumOf19));
    
            // PART (b)
            System.out.println("\nPART (b)");
            int[][] diverse2DArr = {
                {2, 3, 5, 6}, // sum: 16
                {5, 9, 2, 4}, // sum: 20
                {9, 9, 8, 4}, // sum: 30
                {1, 4, 3, 2} // sum: 10
            };
            int[][] nonDiverse2DArr = {
                {2, 5, 3, 6}, // sum: 16
                {5, 9, 4, 1}, // sum: 19
                {7, 9, 4, 8}, // sum: 28
                {3, 2, 6, 5} // sum: 16
            };
            System.out.println("rowSum test: 2D array with sums [16, 20, 30, 10] returns: " + Arrays.toString(rowSums(diverse2DArr)));
            System.out.println("rowSum test: 2D array with sums [16, 19, 28, 16] returns: " + Arrays.toString(rowSums(nonDiverse2DArr)));
            
            // PART (c)
            System.out.println("\nPART (c)");
            // uses arrays from previous part in main
            System.out.println("Diverse array test: Is it diverse? " + isDiverse(diverse2DArr));
            System.out.println("Non-diverse array test: Is it diverse? " + isDiverse(nonDiverse2DArr));
        }
    }
    
    DiverseArray.main(null);
    
    PART (a)
    arraySum test: array with a sum of 7 returns: 7
    arraySum test: array with a sum of 19 returns: 19
    
    PART (b)
    rowSum test: 2D array with sums [16, 20, 30, 10] returns: [16, 20, 30, 10]
    rowSum test: 2D array with sums [16, 19, 28, 16] returns: [16, 19, 28, 16]
    
    PART (c)
    Diverse array test: Is it diverse? true
    Non-diverse array test: Is it diverse? false