Home > Software engineering >  How to filter objects contained in two Sets based on a single property without overriding equals() a
How to filter objects contained in two Sets based on a single property without overriding equals() a

Time:05-10

I have a set of objects and trying to find if an object exist in list by id. I do not want to override equals() and hashCode().

class ABC {
    Long id;
    String name;
}

I want to do the below statement without overriding equals() and hashCode() methods

Set<ABC> abcSetOne;
Set<ABC> abcSetTwo;

abcSetOne.stream()
   .filter(abcSetTwo::contains)
   .collect(Collectors.toSet());

ids are guaranteed unique.

I am using Java 8.

CodePudding user response:

Update

When need set intersection (in terms of set theory) of your object based on one attribute only without changing the existing hashCode() and equals() methods, you can create a HashSet of ids.

public static void main(String[] args) {
    Set<ABC> abcSetOne = Set.of(new ABC(1L, "first"), new ABC(2L, "second"), new ABC(3L, "third"));
    Set<ABC> abcSetTwo = Set.of(new ABC(1L, "first"), new ABC(5L, "fifth"), new ABC(3L, "third"));
    
    Set<Long> idsOne = abcSetTwo.stream()
        .map(ABC::getId)
        .collect(Collectors.toSet());
    
    Set<ABC> result = abcSetOne.stream()
        .filter(abc -> idsOne.contains(abc.getId()))
        .collect(Collectors.toSet());
    
    System.out.println(result);
}

Output

[ABC{id=1, name='first'}, ABC{id=3, name='third'}]

When you need to establish uniqueness based on more than one object's property, you can define a wrapper class with the hashCode/equals contract implemented based on these properties.

As a wrapper you can utilize of Java 16 record, that will make the code leaner (hashCode() and equals() will be generated by the compiler)

public record ABCWrapper(Long id, String name) {
    ABCWrapper(Wrapping.ABC abc) {
        this(abc.getId(), abc.getName());
    }
}

For earlier versions, ABCWrapper can be defined as a plain class.

main() - demo

public static void main(String[] args) {
    Set<ABC> abcSetOne = Set.of(new ABC(1L, "first"), new ABC(2L, "second"), new ABC(3L, "third"));
    Set<ABC> abcSetTwo = Set.of(new ABC(1L, "first"), new ABC(5L, "fifth"), new ABC(3L, "third"));
    
    Map<ABCWrapper, ABC> abcByWrapper = abcSetTwo.stream()
        .collect(Collectors.toMap(ABCWrapper::new, Function.identity()));
    
    Set<ABC> result = abcSetOne.stream()
        .map(ABCWrapper::new)
        .filter(abcByWrapper::containsKey)
        .map(abcByWrapper::get)
        .collect(Collectors.toSet());

    System.out.println(result);
}

Output

[ABC{id=1, name='first'}, ABC{id=3, name='third'}]
  • Related