views:

250

answers:

6

Simple question.

I have a new list and an old list. In Java is there a standard way/library that allows me to compare these two lists and determine which items have been updated/deleted or are completely new? E.g. I should end up with three lists - Deleted items (items in old but not in new), Updated items (items in both), New items (items in new and not in old).

I could write this myself but was wondering if there is a standard way to do it.

The objects in the list implement equals correctly.

+1  A: 

I would use Apache CollectionUtils and use the union (items in both) and disjunction functions (change the order to get one or the other).

Ideally you'd make one pass over all the elements instead of 3, but if this isn't your bottleneck, I wouldn't worry about efficiency right now.

I82Much
+2  A: 

There's nothing in the standard libraries.

However the Apache Commons CollectionUtils class gives you this functionality with the intersection and subtract methods:

Collection<T> old = ...;
Collection<T> neww = ...;

Collection<T> deleted = (Collection<T>)CollectionUtils.subtract(old, new);
Collection<T> updated = (Collection<T>)CollectionUtils.intersection(old, new);
Collection<T> newResult = (Collection<T>)CollectionUtils.subtract(new, old);

(You need the (unchecked) casts because CollectionUtils isn't generified.)

Andrzej Doyle
+6  A: 

No standard way sorry. You can do it fairly easily with the standard JDK without resorting to adding a dependency on Apache Commons (as others have suggested) however. Assuming your lists are List<T> instances:

List<T> oldList = ...
List<T> newList= ...

List<T> removed = new ArrayList<T>(oldList);
removed.removeAll(newList);

List<T> same = new ArrayList<T>(oldList);
same.retainAll(newList);

List<T> added = new ArrayList<T>(newList);
added.removeAll(oldList);
cletus
+1 - yeah, much better than mine.
Andrzej Doyle
Unfortunately this is slightly wrong... removeAll and similar operate on the passed in list and return a boolean. So that won't compile. Needs to be:List<T> added = new ArrayList<T>(newList);added.removeAll(oldList); etc...So there might be a case for the apache commons methods after all...
Pablojim
@Pablojim: quite right, thanks. Fixed.
cletus
Thanks for this
Alberto Zaccagni
+1  A: 

I think you can accomplish this with the standard java library too. Take a look at the following methods of java.util.Collection:

retainAll(Collection c)

Retains only the elements in this collection that are contained in the specified collection (optional operation). In other words, removes from this collection all of its elements that are not contained in the specified collection.

removeAll(Collection c)

Removes all this collection's elements that are also contained in the specified collection (optional operation). After this call returns, this collection will contain no elements in common with the specified collection.

NickDK
A: 

If there is a standard way, I don't know it...
I looked at Collections but only saw disjoint() (that's already an information...) and indexOfSubList() (not sure if it is useful at all).
I also looked at Google Collections and if there is, apparently, not such facility, there are some useful tools there, like Collections2's filter() function which can help if you make a proper Predicate.

[EDIT] I missed the removeAll and retainAll methods of Collection... I don't delete this answer, even if a bit pathetic, as it is somehow complementary of the other answers... (I think Google Collections is at least worth mentioning!)

PhiLho
A: 

Personally, I believe that the only sensible way to explain the difference between two lists is with a full-blown diff algorithm (like that of the unix diff command).

Sets, though, are a much simpler story. Google Collections provides a Sets.difference(Set, Set) method, as well as union and intersection.

Kevin Bourrillion