# Finding the Intersection of Arrays

I would like any advice on how to improve this code. To clarify what this code considers an intersection to be, the intersection of [3,3,4,6,7] and [3,3,3,6,7] is [3,6,7]. I would appreciate any improvements to make the code more readable or perform faster.

public ArrayList<Integer> findIt (int[] a, int[] b){
ArrayList<Integer> result = new ArrayList<Integer>();
Arrays.sort(a);
Arrays.sort(b);
int i = 0;
int j = 0;
while(i < a.length && j < b.length){
if(a[i]<b[j])
++i;
else if (a[i] > b[j])
++j;
else{
if (!result.contains(a[i]))
++i;
++j;
}
}
return result;
}

• Examples of given arrays are already sorted. Are all given arrays sorted? If result ArrayList can not contain duplicate elements, maybe Set would be better? Mar 12 '12 at 10:26
• Since the answers are using Lists instead of arrays as input, I'll ask directly: Any special reason you are using arrays? It's very unusual to use arrays in Java, because Lists are much more flexible. Generally, unless you need to optimize extremely for speed, you should reconsider using arrays at all. Mar 13 '12 at 9:42
• You mean "intersection". Mar 13 '12 at 13:26

## Algorithm

You're using a O(n log(n)) algorithm here, which could be O(n²) for difficult cases since contains() is O(n) and is called in a loop. Instead, use the property of HashSet: access is O(1), which means you can achieve this in O(n) time. My algorithm below simply keeps track of what it can add to the result. I can add everything that exists in the first list, but I should not add an item I already added.

See my tested code for my implementation:

public static List<Integer> intersection(List<Integer> a, List<Integer> b){
Set<Integer> canAdd = new HashSet<Integer>(a);
List<Integer> result = new ArrayList<Integer>();

for (int n: b) {
if(first.contains(n)) {
// we wish to add only one n
}
}

return result;
}


1. You should return a List, not an ArrayList since it's an implementation detail. Using an ArrayList is OK here since adding at the end of it has O(1) amortized complexity. Otherwise, lists should be LinkedList (when adding to the beginning, not to the end, as @Landei points out).
2. Be careful about the names you choose. findIt doesn't seem to be appropriate, but removeDuplicates or intersection describes what the code does.
• I agree with everything except with the LinkedList comment. Benchmarks show that ArrayList is almost always preferable. See e.g. javaspecialists.eu/archive/Issue111.html Mar 12 '12 at 15:18
• You use a reference first, but it isn't defined (your code won't compile). If it's a or b, you have a nasty side-effect. Mar 12 '12 at 16:07
• @Landei Oops, I meant to use addFirst. Since it's not always available in the List interface, I'll switch back to ArrayList. @X-Zero Opps, that's canAdd, I forgot to change that one. Mar 12 '12 at 16:53
• @seand Haha, so this is why I couldn't understand what an "interception" was. Mar 13 '12 at 17:25

@Cygal : Assuming that HashSet.contains() is really faster than the List one, this could be the ultimate code :-)

public static List<Integer> intersection(List<Integer> a, List<Integer> b) {
Set<Integer> aSet = new HashSet<Integer>(a);
Set<Integer> bSet = new HashSet<Integer>(b);

for(Iterator<Integer> it = aSet.iterator(); it.hasNext();) {
if(!bSet.contains(it.next())) it.remove();
}

return new ArrayList<Integer>(aSet);
}

• 'aSet' is a local variable so it cannot be modified from anywhere else. It should be good :-) Merci ! Mar 13 '12 at 13:15
• I don't know if this is about concurrent accesss or "removing while doing a for loop". Maybe this works and is specified, but I would not do this in production code unless I was sure. (That's forbidden in C++, by the way.) Mar 13 '12 at 13:22
• In Java, the only way to remove an Object from a collection is to use an Iterator. This note is applicable only if there is a concurrent access. Trust me, it works well ;-) Mar 13 '12 at 13:30

What about ? It's clean.

public static List<Integer> intersection(List<Integer> a, List<Integer> b){
List<Integer> result = new ArrayList<Integer>();

for(int v : a) {
if(b.contains(v) && !result.contains(v)) {
}
}

// sort if you need
Collections.sort(result);

return result;
}

• It's simply a performance issue: List.contains takes a lot of time compared to HashSet.contains(): O(1) vs O(n). Otherwise, it's nice and easy to read, here's an upvote. :) Mar 13 '12 at 10:05
• Side note: you should use for (Integer instead of for (int because you're unnecessarily boxing and unboxing as a result. Mar 15 '12 at 6:19

You can use CollectionUtils utility in Apache Commons Collection. There is intersection method in this class. I will write my utility for your case in following:

public <T> Collection<T> intersection(T[] one, T[] two)
{
List<T> list_one = Arrays.asList(one);
List<T> list_two = Arrays.asList(two);

List<T> intersection = (List<T>) org.apache.commons.collections
.CollectionUtils.intersection(list_one, list_two);

return intersection;
}


I hope my answer will useful for you.