CookieOrder / MasterOrder: 2010 FRQ 1
A step-by-step solution to the 2010 AP CSA FRQ 1 (CookieOrder / MasterOrder), covering summing values across an ArrayList and safely removing matching elements while iterating in Java.
Selling boxes of cookies for a fundraiser is the backdrop for this AP Computer Science A free-response question, and it hands you a list of custom objects to work with instead of a plain array — first totaling a value across every element, then safely removing some of them while you're still in the middle of scanning the list.
What This FRQ Tests
- AP CSA units: Unit 7 (ArrayList) and Unit 4 (Iteration)
- Core skill: traversing a
Listof custom objects to accumulate a numeric total - Secondary skill: removing matching elements from an
ArrayListmid-traversal without accidentally skipping any - Official category: content-wise, this is an "Array/ArrayList" question — but 2010 predates the standardized FRQ-number-to-category order that AP CSA settled into starting with the 2019–2020 Course and Exam Description redesign. The exam booklet itself prints this question as FRQ 1, so that's the number used here, even though a modern exam would slot ArrayList-based work into the FRQ 3 position instead.
The Setup
- The given
CookieOrderclass (not modified) provides:- A constructor:
CookieOrder(String variety, int numBoxes) String getVariety()— the cookie variety for this orderint getNumBoxes()— how many boxes were ordered
- A constructor:
MasterOrderholds:private List<CookieOrder> orders— built asnew ArrayList<CookieOrder>()in the constructorvoid addOrder(CookieOrder theOrder)— already written; appends toorders
- You're asked to write two methods:
getTotalBoxes()— the sum ofgetNumBoxes()across every order in the listremoveVariety(String cookieVar)— removes every order matchingcookieVarand returns the total boxes removed
Part (a): Writing getTotalBoxes()
Step-by-Step Approach
- Start a running total at
0. - Loop over every index of
orders. - On each iteration, pull out that
CookieOrderand add its box count to the total. - After the loop, return the total.
The Code
public int getTotalBoxes()
{
int total = 0;
for (int i = 0; i < orders.size(); i++)
{
total += orders.get(i).getNumBoxes();
}
return total;
}
Why Each Piece Matters
orders.get(i).getNumBoxes()—get(i)returns theCookieOrderobject at that position; you then callgetNumBoxes()on that object to get the number you actually want to add.- Starting
totalat0— this automatically handles the "no cookie orders" case correctly. Ifordersis empty, the loop body never runs, and0is returned as-is — no special-caseifneeded. orders.size(), not a hardcoded number — the list can hold any number of orders, so the loop bound has to come from the list itself.
Common Mistakes to Avoid
- Adding the
CookieOrderobject itself instead ofgetNumBoxes().total += orders.get(i);doesn't even compile — you must go through the getter to reach theintyou need. - Off-by-one on the loop bound. Using
i <= orders.size()instead ofi < orders.size()callsget(...)one index past the end of the list. - Re-declaring
totalinside the loop. Declaringint total = 0;inside the loop body resets it to0every iteration instead of accumulating.
Part (b): Writing removeVariety(String cookieVar)
The Rule, Broken Down
- Every order in
orderswhose variety matchescookieVargets removed from the list. - Before removing an order, its box count gets added to a running total.
- There can be zero, one, or several matching orders — the method has to handle all of those correctly.
- The method returns the total boxes removed, whether that's
0or a large number.
Step-by-Step Approach
- Start a running total at
0. - Loop over
orders, but backwards — from the last index down to0. - On each iteration, check whether that order's variety matches
cookieVar. - If it matches, add its box count to the total, then remove it from the list.
- After the loop finishes, return the total.
The Code
public int removeVariety(String cookieVar)
{
int totalRemoved = 0;
for (int i = orders.size() - 1; i >= 0; i--)
{
CookieOrder order = orders.get(i);
if (order.getVariety().equals(cookieVar))
{
totalRemoved += order.getNumBoxes();
orders.remove(i);
}
}
return totalRemoved;
}
Why the Backward Loop Matters
- Removing from an
ArrayListshifts every later element one position to the left. If you're looping forward and you remove the element at indexi, the element that used to be ati + 1slides into indexi— but a forward loop then increments toi + 1next, silently skipping the element that just slid intoi. - Looping backward avoids this entirely. When you remove index
i, only elements at indices greater thanishift — and a backward loop has already finished visiting those. The remaining indices you still need to check (everything less thani) are completely untouched by the shift. order.getVariety().equals(cookieVar)— always compareStringcontents with.equals(). Two differentStringobjects holding the same characters aren't guaranteed to be==.
Tracing the Example
Using the question's own code segment — goodies starts with orders ("Chocolate Chip", 1), ("Shortbread", 5), ("Macaroon", 2), ("Chocolate Chip", 3) at indices 0–3. Tracing goodies.removeVariety("Chocolate Chip") with the backward loop:
i |
Order at i |
Matches? | totalRemoved |
List after this step |
|---|---|---|---|---|
| 3 | ("Chocolate Chip", 3) |
yes | 3 | ["Chocolate Chip" 1, "Shortbread" 5, "Macaroon" 2] |
| 2 | ("Macaroon", 2) |
no | 3 | unchanged |
| 1 | ("Shortbread", 5) |
no | 3 | unchanged |
| 0 | ("Chocolate Chip", 1) |
yes | 4 | ["Shortbread" 5, "Macaroon" 2] |
The method returns 4, and the list ends up as ["Shortbread" 5, "Macaroon" 2] — both match the question exactly. A follow-up call to goodies.removeVariety("Brownie") finds no matches at any index, so totalRemoved stays 0 and the list is untouched, also matching the question.
Common Mistakes to Avoid
- Looping forward and removing as you go. This is the single most common bug on this exact style of problem — it silently skips whichever order slides into the just-vacated index.
- Comparing varieties with
==instead of.equals(). This is one of the most frequent AP CSA point losses anywhereStringcomparison appears. - Adding the box count after removing the order, or trying to read
getNumBoxes()from a reference obtained afterremove(i)already ran. Grab the object withget(i)and read what you need from it before removing it. - Forgetting the method still needs to return
0correctly when nothing matches — this falls out naturally as long astotalRemovedstarts at0and theifsimply never triggers.
Notes: A Simpler Removal Pattern Not on the Quick Reference Sheet
Java's Iterator interface offers a pattern that sidesteps the whole "which direction should I loop" question entirely, since it.remove() always removes whatever element it.next() most recently returned, safely:
import java.util.Iterator;
public int removeVariety(String cookieVar)
{
int totalRemoved = 0;
Iterator<CookieOrder> it = orders.iterator();
while (it.hasNext())
{
CookieOrder order = it.next();
if (order.getVariety().equals(cookieVar))
{
totalRemoved += order.getNumBoxes();
it.remove();
}
}
return totalRemoved;
}
- The
Iteratorclass isn't listed on the AP Quick Reference sheet at all — onlyArrayList's ownsize/add/get/set/removemethods are. That doesn't mean using anIteratoris against the rules; it's completely valid Java and a completely valid thing to write on the real exam. The only real tradeoff is that you won't have its exact behavior printed for you to double-check mid-exam the way you would with the backward-loop version above. it.remove()is specifically designed to be safe to call immediately afterit.next(), which is exactly why this pattern avoids the index-shifting problem without needing to reason about loop direction at all.
Key Takeaways
- Removing elements from an
ArrayListwhile scanning it is a recurring AP CSA trap — loop backward (or use anIterator), never forward with a plain index. - When a method needs to report "how much got removed," accumulate from each matching element before removing it, not after.
Stringfields always compare with.equals(), never==, regardless of how the surrounding loop is structured.