Topic: Array and ArrayList manipulation with String processing
Skills Tested: Array traversal, ArrayList creation, String methods (indexOf, substring), data filtering, enhanced vs regular for loops
Curriculum Alignment: Unit 4 (ArrayList), Unit 6 (Array)
Question
Users of a website are asked to provide a review of the website at the end of each visit. Each review, represented by an object of the Review class, consists of an integer indicating the user's rating of the website and an optional String comment field.
Provided Review Class
public class Review {
private int rating;
private String comment;
/** Precondition: r >= 0
* c is not null. */
public Review(int r, String c) {
rating = r;
comment = c;
}
public int getRating() {
return rating;
}
public String getComment() {
return comment;
}
// There may be instance variables, constructors, and methods
// that are not shown.
}
ReviewAnalysis Class
The ReviewAnalysis class contains methods used to analyze the reviews provided by users. You will write two methods of the ReviewAnalysis class.
public class ReviewAnalysis {
/** All user reviews to be included in this analysis */
private Review[] allReviews;
/** Initializes allReviews to contain all the Review objects
* to be analyzed */
public ReviewAnalysis() {
/* implementation not shown */
}
/** Returns a double representing the average rating of all
* the Review objects to be analyzed, as described in part (a)
* Precondition: allReviews contains at least one Review.
* No element of allReviews is null. */
public double getAverageRating() {
/* to be implemented in part (a) */
}
/** Returns an ArrayList of String objects containing formatted
* versions of selected user comments, as described in part (b)
* Precondition: allReviews contains at least one Review.
* No element of allReviews is null.
* Postcondition: allReviews is unchanged. */
public ArrayList<String> collectComments() {
/* to be implemented in part (b) */
}
}
Part (a): Write getAverageRating Method
Write the getAverageRating method, which returns the average rating (arithmetic mean) of all elements of allReviews.
For example, if allReviews contains the following Review objects:
| Index | Rating | Comment |
|---|---|---|
| 0 | 5 | "Great site!" |
| 1 | 4 | "" |
| 2 | 4 | "Good" |
| 3 | 4 | "Helped me a lot!" |
| 4 | 3 | "Cool" |
Then getAverageRating() should return 4.0 (calculated as (5+4+4+4+3)/5 = 20/5 = 4.0)
Part (b): Write collectComments Method
Write the collectComments method, which collects and formats only comments that contain an exclamation point ("!"). The method returns an ArrayList of String objects containing copies of user comments from allReviews that contain an exclamation point, formatted as follows:
- The String inserted into the ArrayList begins with the index of the Review in allReviews
- The index is immediately followed by a hyphen ("-")
- The hyphen is followed by a copy of the original comment
- The String must end with either a period (".") or an exclamation point ("!")
- If the original comment from allReviews does not end in either a period or an exclamation point, a period is added
An empty ArrayList is returned if no comment in allReviews contains an exclamation point.
Example:
Using the same allReviews from part (a), the following ArrayList would be returned by a call to collectComments():
| Index | Value |
|---|---|
| 0 | "0-Great site!" |
| 1 | "3-Helped me a lot!" |
Note: The reviews at index 1, 2, and 4 in allReviews are not included in the ArrayList to return since none of those reviews contains an exclamation point.
Solution & Explanation
Part (a) Solution: getAverageRating
public double getAverageRating() {
int sum = 0;
for (Review r : allReviews) {
sum += r.getRating();
}
return sum / (double) allReviews.length;
}
Step-by-Step Explanation:
-
Initialize accumulator:
int sum = 0;to store the total of all ratings -
Enhanced for loop:
for (Review r : allReviews)- Iterates through each Review object in the array
- Enhanced for loop is appropriate here because we don't need the index
- Variable
rrepresents each Review object
-
Accumulate ratings:
sum += r.getRating();- Call
getRating()on each Review object - Add the rating to the running sum
- Call
-
Calculate and return average:
return sum / (double) allReviews.length;- Divide sum by the number of reviews
-
Critical: Cast to
(double)to get decimal result - Without the cast, integer division would truncate (e.g., 17/5 = 3, not 3.4)
- Enhanced for loop is valid here (and cleaner than regular for loop)
- Must cast to
doubleto avoid integer division - Can cast either the sum or the length:
(double) sum / allReviews.lengthalso works
Part (b) Solution: collectComments
public ArrayList<String> collectComments() {
ArrayList<String> result = new ArrayList<String>();
for (int i = 0; i < allReviews.length; i++) {
String comment = allReviews[i].getComment();
if (comment.indexOf("!") >= 0) {
String formatted = i + "-" + comment;
String lastChar = formatted.substring(formatted.length() - 1);
if (!lastChar.equals(".") && !lastChar.equals("!")) {
formatted += ".";
}
result.add(formatted);
}
}
return result;
}
Step-by-Step Explanation:
-
Create result ArrayList:
ArrayList<String> result = new ArrayList<String>();- Will hold the formatted comments
- Initialized as empty
-
Regular for loop:
for (int i = 0; i < allReviews.length; i++)- Must use regular for loop (not enhanced) because we need the index
- Index is required for formatting: "index-comment"
-
Get comment:
String comment = allReviews[i].getComment();- Retrieve the comment String from current Review
-
Check for exclamation point:
if (comment.indexOf("!") >= 0)-
indexOf("!")returns the index of "!" or -1 if not found -
>= 0means "!" was found - Only process comments containing "!"
-
-
Format the string:
String formatted = i + "-" + comment;- Concatenate index, hyphen, and comment
- Example: "0-Great site!"
-
Check last character:
String lastChar = formatted.substring(formatted.length() - 1);-
substring(start)from start position to end -
formatted.length() - 1is the index of the last character - Gets the last character as a String
-
-
Add period if needed:
if (!lastChar.equals(".") && !lastChar.equals("!"))- Check if last char is NOT "." and NOT "!"
- If true, add a period:
formatted += "."; - Use
equals()for String comparison
-
Add to result:
result.add(formatted);- Add the formatted comment to the ArrayList
-
Return result:
return result;- Return the ArrayList (may be empty if no comments had "!")
- Must use regular for loop to get index (enhanced for won't work)
-
indexOf("!")is the standard way to check if String contains a substring -
substring(start)goes from start to end of String - Must check for BOTH "." and "!" in the ending condition
- Use
equals()not==for String comparison
Detailed Explanation
Key Concepts Tested
1. Enhanced vs Regular For Loops
Part (a) — Enhanced For Loop:
for (Review r : allReviews) {
// Use r to access Review methods
}
When to use: When you only need to access elements, not their indices
Part (b) — Regular For Loop:
for (int i = 0; i < allReviews.length; i++) {
// Use i to get index for formatting
}
When to use: When you need the index position of elements
2. Integer vs Double Division
// ❌ WRONG - Integer division
return sum / allReviews.length; // 17/5 = 3
// ✅ CORRECT - Double division
return sum / (double) allReviews.length; // 17/5 = 3.4
In Java, dividing two integers always produces an integer result (truncated). To get a decimal result, at least one operand must be a double.
3. String Methods
indexOf(String str): Returns index of first occurrence of str, or -1 if not found
"Hello!".indexOf("!") // returns 5
"Hello".indexOf("!") // returns -1
substring(int start): Returns substring from start index to end
"Hello!".substring(5) // returns "!"
"Hello!".substring(6) // returns ""
equals(String str): Compares String content
"!".equals("!") // true
"!" == "!" // may be false (compares references)
4. ArrayList Operations
// Create new ArrayList
ArrayList<String> list = new ArrayList<String>();
// Add element
list.add("item");
// Return ArrayList (even if empty)
return list;
Why These Design Choices?
Part (a): Uses enhanced for loop because we only need to sum the ratings, not track positions.
Part (b): Uses regular for loop because we must include the index in the formatted output ("0-comment").
Filtering pattern: Part (b) demonstrates a common pattern:
- Create empty result collection
- Loop through source data
- Check condition (contains "!")
- If true, process and add to result
- Return result
Common Mistakes to Avoid
Part (a) Common Errors
- ❌ Integer division:
return sum / allReviews.length;(no cast to double) - ❌ Wrong loop: Using
allReviews.size()instead ofallReviews.length(it's an array, not ArrayList) - ❌ Not accumulating: Forgetting to add to sum:
sum = r.getRating(); - ❌ Direct field access: Trying
r.ratinginstead ofr.getRating()
Part (b) Common Errors
- ❌ Using enhanced for loop: Can't get index with
for (Review r : allReviews) - ❌ Wrong String search: Using
contains("!")(doesn't exist) instead ofindexOf("!") >= 0 - ❌ Wrong substring:
substring(formatted.length())(index out of bounds) - ❌ Using == for Strings:
lastChar == "."instead oflastChar.equals(".") - ❌ Missing OR logic: Only checking for "." but not "!" in the ending condition
- ❌ Wrong concatenation order:
comment + "-" + iinstead ofi + "-" + comment - ❌ Modifying original: Trying to modify the Review objects instead of creating new Strings
- ❌ Return type: Returning array instead of ArrayList
General Errors
- ❌ Array vs ArrayList confusion:
allReviewsis an array, use.lengthnot.size() - ❌ Null checks: Adding unnecessary null checks (precondition says no nulls)
Scoring Rubric
Part (a): 4 Points
| Point | Criteria |
|---|---|
| 1 | Accesses all ratings (loop through allReviews) |
| 1 | Calls getRating() on Review objects |
| 1 | Computes sum of all ratings |
| 1 | Divides by array length and returns double (proper casting) |
Part (b): 5 Points
| Point | Criteria |
|---|---|
| 1 | Creates and returns ArrayList<String> |
| 1 | Accesses all comments in allReviews |
| 1 | Identifies comments containing "!" using indexOf or similar |
| 1 | Formats String correctly with index-comment |
| 1 | Adds period if String doesn't end with "." or "!", adds to ArrayList |
Total: 9 points possible
📄 Official College Board Resources
Written by Tanner, Certified AP Computer Science Teacher with 5+ years teaching AP CSA.
Last updated: