19

I have two Collections in a Java class.The first collection contains previous data, the second contains updated data from the previous collection.

I would like to compare the two collections but I'm not sure of the best way to implement this efficiently.Both collections will contain the same amount of items.

Based then on the carType being the same in each collection I want to execute the carType method.

Any help is appreciated

damien535
  • 627
  • 3
  • 14
  • 31
  • 4
    http://stackoverflow.com/questions/23445/how-best-to-compare-two-collections-in-java-and-act-on-them – jmj Nov 03 '10 at 08:52
  • What result do you expect from the comparison; you want to extract the elements that didn't change ? do you need to know their index in the collections (it's the same in both)... – pgras Nov 03 '10 at 08:57
  • Apologies for the vague description pgras. The collections will be in the same order and the same size.Some of the data in the new collection will be updated from the previous collection.Based on carType,registrationNo and insurancePolicy being the same in both collections I will then execute some other code. – damien535 Nov 03 '10 at 09:13
  • Future readers. If you want to compare two collections.... based on the value(s) of SOME (or all) of the scalar properties of the ITEMs in the collection : see https://stackoverflow.com/questions/40717638/how-to-compare-two-collections-for-equivalence-based-on-fields-from-different/40718320#40718320 – granadaCoder Mar 22 '21 at 14:43

6 Answers6

30

Difficult to help, because you didn't tell us how you like to compare the (equal-size) collections. Some ideas, hoping one will fit:

Compare both collections if they contain the same objects in the same order

Iterator targetIt = target.iterator();
for (Object obj:source)
  if (!obj.equals(targetIt.next()))
    // compare result -> false

Compare both collections if they contain the same objects in the any order

for (Object obj:source)
  if (target.contains(obj))
    // compare result -> false

Find elements in other collection that has changed

Iterator targetIt = target.iterator();
for (Object obj:source)
  if (!obj.equals(targetIt.next())
    // Element has changed

Based on your comment, this algorithm would do it. It collects all Cars that have been updated. If the method result is an empty list, both collections contain equal entries in the same order. The algorithm relies on a correct implementation of equals() on the Car type!

public List<Car> findUpdatedCars(Collection<Car> oldCars, Collection<Car> newCars)
  List<Car> updatedCars = new ArrayList<Car>();
  Iterator oldIt = oldCars.iterator();
  for (Car newCar:newCars) {
    if (!newCar.equals(oldIt.next()) {
      updatedCars.add(newCar);
    }
  }
  return updatedCars;
}
Shervin Asgari
  • 23,901
  • 30
  • 103
  • 143
Andreas Dolk
  • 113,398
  • 19
  • 180
  • 268
20

From the set arithmetics, the sets A and B are equal iff A subsetequal B and B subsetequal A. So, in Java, given two collections A and B you can check their equality without respect to the order of the elements with

boolean collectionsAreEqual = A.containsAll(B) && B.containsAll(A);
RedXIII
  • 781
  • 7
  • 6
  • 4
    this statement is true for sets but may not be true for lists or other structures that permit duplicate entries (in other words, use sets when possible to simplify your logic) – cfeduke Jun 02 '15 at 19:51
6
  • Iterate over the first collection and add it into a Map<Entity, Integer> whereby Entity is the class being stored in your collection and the Integer represents the number of times it occurs.
  • Iterate over the second collection and, for each element attempt to look it up in the Map - If it exists then decrement the Integer value by one and perform any action necessary when a match is found. If the Integer value has reached zero then remove the (Entity, Integer) entry from the map.

This algorithm will run in linear time assuming you've implemented an efficient hashCode() method.

Adamski
  • 54,009
  • 15
  • 113
  • 152
3

Slightly updated one considering null values:

static <T> boolean equals(Collection<T> lhs, Collection<T> rhs) {
    boolean equals = false;
    if(lhs!=null && rhs!=null) {
       equals = lhs.size( ) == rhs.size( ) && lhs.containsAll(rhs)  && rhs.containsAll(lhs);
    } else if (lhs==null && rhs==null) {
       equals = true;
    }
 return equals;
}
Rakesh
  • 4,004
  • 2
  • 19
  • 31
2

If not worried about cases like (2,2,3), (2,3,3):

static <T> boolean equals(Collection<T> lhs, Collection<T> rhs) {
    return lhs.size( ) == rhs.size( ) && lhs.containsAll(rhs)  && rhs.containsAll(lhs);
}
gerardw
  • 5,822
  • 46
  • 39
0
public static boolean isEqualCollection(java.util.Collection a,
                                        java.util.Collection b)

Returns true if the given Collections contain exactly the same elements with exactly the same cardinalities.

That is, iff the cardinality of e in a is equal to the cardinality of e in b, for each element e in a or b.

Parameters:

  • the first collection, must not be null
  • the second collection, must not be null

Returns: true if the collections contain the same elements with the same cardinalities.

lkatiforis
  • 5,703
  • 2
  • 16
  • 35
bithub
  • 77
  • 10