2

I'm having two collections of Foo. I can not change the implementation of Foo and Foo's equals function is implemented incorrectly. I can also not inherit from Foo. I do custom equality function: I've implemented using guava's Predicate function. To give you an idea, the implementation looks a bit like this.

new Predicate<Pair<Foo, Foo>>() {
        @Override
        public boolean apply(@Nullable Pair<Foo, Foo> input) {
          Foo one = input.getFirst();
          Foo two = input.getSecond();
          return Objects.equals(one.getId(), two.getId());
        }
      };

Now I need to check if my two collections of Foo contain the same items ignoring the order

I'm looking for the best way to do this using this custom equality function.

Hendrik
  • 1,355
  • 3
  • 11
  • 30
  • 1
    Can you use Sets instead? Otherwise you could check that list2 `containsAll` items from list1 and vice versa. – mvd Oct 15 '15 at 01:26
  • Any implementation of Set that I know uses the equals function for equality. If there was an implementation of set where you can define a custom equality function like the one I had (or similar) then that would be a great solution – Hendrik Oct 15 '15 at 17:27

3 Answers3

5

You could wrap your class in a Guava Equivalence and store that in the Sets.

Equivalence<Foo> eq = new Equivalence<Foo>{
// implement equals and hashcode
};
Set<Equivalence<Foo>> set1 = new HashSet<>();
set1.add(eq.wrap(someFoo));

That way you could do a bidirectional containsAll() or do

Sets.difference(set1, set2).isEmpty()
Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
1

Instead of a custom Predicate, why not a simple SortedSet with custom Comparator?

    Comparator<Foo> comparator = new Comparator<Foo>() {

        public int compare(Foo o1, Foo o2) {
            return //your custom comparison
        }
    };
    SortedSet<Foo> sortedSet1 = newTreeSet(comparator);
    sortedSet1.addAll(firstCollection);
    SortedSet<Foo> sortedSet2 = newTreeSet(comparator);
    sortedSet2.addAll(secondCollection);

    sortedSet1.equals(sortedSet); //this is what you want
Omar Hrynkiewicz
  • 502
  • 1
  • 8
  • 21
  • While this should technically work, it violates the contract of Comparator which suggests that a 0 is returned iff the two objects are equal – Sean Patrick Floyd Oct 15 '15 at 20:48
-2

If you don't want to have sorted list after operation, copy it or use answer with Set (but with Set [1,1,1] == [1]).

public class ListTest {
    public static void main(String[] args) {
        List<Integer> list1 = Arrays.asList(1, 2, 3, 4, 5);
        List<Integer> list2 = Arrays.asList(1, 2, 3, 4, 5);
        List<Integer> list3 = Arrays.asList(1, 2, 3, 4, 4);

        System.out.println(compare(list1, list2, (a, b) -> a - b));
        System.out.println(compare(list1, list3, (a, b) -> a - b));
    }

    private static <E> boolean compare(List<E> list1, List<E> list2, Comparator<E> comparator) {
        if(list1.size() != list2.size()) {
            return false;
        }
        Collections.sort(list1, comparator);
        Collections.sort(list2, comparator);
        Iterator<E> iterator1 = list1.iterator();
        Iterator<E> iterator2 = list2.iterator();
        while (iterator1.hasNext()) {
            if(comparator.compare(iterator1.next(), iterator2.next()) != 0) {
                return false;
            }
        }
        return true;
    }
}
Mati
  • 2,476
  • 2
  • 17
  • 24