Saturnian
Saturnian

Reputation: 1948

How to work with Set Differences in Java using objects?

I need to obtain a set difference between two sets/lists but the objects in these sets are constructed differently. I would like the set difference be calculated on only one field of these objects, how can I do this?

POJO o1 = new POJO();
o1.setName("Bean");
o1.setLocation("Boston");

POJO o2 = new POJO();
o2.setName("Bagel");
o2.setLocation("NYC");

POJO o3 = new POJO();
o3.setName("Bean");

List<POJO> p1 = new ArrayList<>();
p1.add(o1);
p1.add(o2);

List<POJO> p2 = new ArrayList<>();
p2.add(o3);

Collection<POJO> subList = CollectionUtils.subtract(p1, p2);
System.out.println("subList: "+subList.toString());

The output I see is : subList: [POJO(name=Bean)] i.e. o3. But for my use case, o1 and o3 are the same - how can I achieve this? I overrode the default equals() method as well but i don't think it is invoked.

Upvotes: 3

Views: 1008

Answers (2)

Donald Raab
Donald Raab

Reputation: 6686

You can use a UnifiedSetWithHashingStrategy from Eclipse Collections:

POJO o1 = new POJO();
o1.setName("Bean");
o1.setLocation("Boston");

POJO o2 = new POJO();
o2.setName("Bagel");
o2.setLocation("NYC");

POJO o3 = new POJO();
o3.setName("Bean");

HashingStrategy<POJO> strategy = HashingStrategies.fromFunction(POJO::getName);

MutableSet<POJO> set1 =
        HashingStrategySets.mutable.with(strategy, o1, o2);
MutableSet<POJO> set2 =
        HashingStrategySets.mutable.with(strategy, o3);
MutableSet<POJO> difference = set1.difference(set2);

Assert.assertEquals("[POJO(name=Bagel)]", difference.toString());

This answer explains how UnifiedSetWithHashingStrategy works in more detail.

Note: I am a committer for Eclipse Collections.

Upvotes: 4

Pavneet_Singh
Pavneet_Singh

Reputation: 37404

You can achieve this with the help of overloaded subtract with predicate.

  1. Override hashcode and equals in POJO class, (and toString for clean output)

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        POJO pojo = (POJO) o;
        return Objects.equals(name, pojo.name);
    }
    
    @Override
    public int hashCode() {
        return name.hashCode();
    }
    
  2. Use Predicate with set as

    Collection<POJO> subList = CollectionUtils.subtract(p1, p2, new Predicate<POJO>() {
        @Override
        public boolean evaluate(POJO object) {
            return p1.contains(object); // might need to make p1 final
        }
    });
    

Result:

subList: [ Bagel ]

Note: Apache common does not support anything like Java 8 BiPredicate

Upvotes: 4

Related Questions