Counting elements across two lists.
Union answers "in either"; intersection answers "in both" — and both reduce to a search across a second list.
When two ArrayLists represent collections of values, two natural questions emerge: how many elements appear in both (intersection), and how many distinct elements appear in either (union)?
The implementation reduces to a familiar pattern: traverse one list, search the other, and tally based on membership. A small helper method — containsValue — makes the logic readable and reusable.
On the AP exam, this combined pattern appears in FRQs that compare two collections — common membership, shared items, distinct totals.
Search the other list; tally based on membership.
Intersection counts when found; union sums one list plus the new ones from the other.
The contains helper
private boolean containsValue(ArrayList<String> list, String target) {
for (String s : list) {
if (s.equals(target)) return true;
}
return false;
}
This is a hand-written existence check using .equals() — the AP-standard idiom for Strings or objects.
Intersection count
public int intersectionCount(ArrayList<String> a, ArrayList<String> b) {
int count = 0;
for (String x : a) {
if (containsValue(b, x)) {
count++;
}
}
return count;
}
For every element of a, ask "is it also in b?" Tally each hit. Result: the number of elements appearing in both lists (counting duplicates in a; see edge cases below).
Union count (distinct elements in either)
public int unionCount(ArrayList<String> a, ArrayList<String> b) {
int count = a.size();
for (String x : b) {
if (!containsValue(a, x)) {
count++;
}
}
return count;
}
Start with every element of a. Add each element of b that isn't already in a. Result: count of distinct values across both lists — assuming a itself has no duplicates.
Edge cases
- Duplicates in
a. Ifacontains"x"twice, intersection counts"x"twice (once for each occurrence). Union over-counts unless you de-duplicate first. - Empty list. Intersection with an empty list is 0. Union with an empty list equals the size of the other.
- Identical lists. Intersection equals
a.size(). Union equalsa.size()too (no new elements added).
Set-style vocabulary on lists.
Borrowed from set theory; applied to ArrayLists.
- Intersection — elements that appear in both lists.
- Union — distinct elements that appear in either list.
- Membership test — checking whether a value is present in a list.
- Contains helper — reusable boolean method for existence checks.
- Distinct count — number of unique values, ignoring repeats.
- De-duplication — removing repeated values before counting.
How union and intersection are tested.
Direction of the check and handling of duplicates dominate.
What FRQ graders check:
- Correct condition direction. Intersection adds when found; union adds when not found.
- String equality with
.equals(). Never==. - Helper method. Writing a
containsValuehelper earns design credit and reads cleanly. - Starting count for union. Begin with
a.size(), then add new elements fromb.
MCQ patterns: trace counts for given pairs of lists; identify which loop produces union vs intersection.
Trace both counts on the same input.
Two methods, two different totals.
Setup. a = ["apple", "banana", "cherry"], b = ["banana", "cherry", "date", "fig"]. Assume no duplicates within either list.
Intersection trace.
- "apple" in
b? No. - "banana" in
b? Yes. count = 1. - "cherry" in
b? Yes. count = 2.
Result: 2.
Union trace.
- Start with
count = a.size() = 3. - "banana" in
a? Yes — don't add. - "cherry" in
a? Yes — don't add. - "date" in
a? No. count = 4. - "fig" in
a? No. count = 5.
Result: 5.
Check. Union total (5) = a.size() + b.size() - intersection (3 + 4 - 2 = 5). The inclusion-exclusion identity holds.
Why this matters. The same helper (containsValue) drives both counts. Recognizing the symmetry simplifies your code and reduces the chance of inverting the condition.
Union and intersection pitfalls.
Most come from inverted conditions or double-counting.
- Counting up when you should count down. Intersection adds when found; union adds when not found.
- Starting union count from 0. Forget the
a.size()base — total comes out far too low. - Using
==for String comparison. Always.equals(). - Double counting on duplicates within
a. The intersection loop counts each occurrence. - Iterating both lists with two for loops manually instead of using a helper. Works but is harder to read; AP rewards the cleaner helper-based code.
- Confusing union with concatenation.
a.size() + b.size()isn't the union count when overlap exists.
Union vs intersection.
Symmetric logic; opposite conditions.
Union / Intersection Reference
AP Quick Reference| Operation | Starting count | Add when |
|---|---|---|
| Intersection | 0 | Element from a IS in b |
| Union | a.size() |
Element from b is NOT in a |
| Check method | Helper: containsValue |
Uses .equals(). |
| Identity | |A ∪ B| = |A| + |B| - |A ∩ B| |
Verify your work this way. |
| Empty input | Intersection 0; union = other.size() | Edge case to verify. |
How to master both counts.
Write the helper once; the two methods almost write themselves.
Use the three practice tools below this lesson in order:
- MCQ Practice — for each problem, write out
aandbon paper. Tally union and intersection by hand, then verify with the inclusion-exclusion identity. - Java Lab — implement
containsValue, then buildintersectionCountandunionCounton top of it. Test with disjoint, overlapping, and identical lists. - FRQ Practice — for any "in both" / "in either" prompt, declare the helper first. The main methods become two-line traversals.
If you can write either count from memory in under a minute, you've mastered the pattern that underlies most multi-list comparisons.
Practice — attempt these now.
AP-style assessments aligned to this lesson. Time them.