Reputation: 19
Given all TypeA
instances in a List<TypeA>
have an instance of SubTypeB
set in the superTypeB field, I need to filter out duplicate TypeA
instances from the list, where a duplicate means the values of propertyA
and propertyB
from the SubTypeB
both match. Is there a way to do this with the Java 8 stream API?
public class TypeA {
private SuperTypeB superTypeB;
public SuperTypeB getSuperTypeB(){ return superTypeB; }
}
public class SuperTypeB {
private String propertyX;
}
public class SubTypeB extends SuperTypeB {
private String propertyA;
private String propertyB;
public String getPropertyA(){ return propertyA; }
public String getPropertyB(){ return propertyB; }
}
Upvotes: 1
Views: 95
Reputation: 31868
You need to be sure to not map
before you filter
to collect to the same type. Using a distinctByKey
utility, you can further choose to collect
to a List
as :
List<TypeA> filteredTypeAs = typeAList.stream()
.filter(distinctByKey(s -> {
SubTypeB subTypeB = (SubTypeB) s.getSuperTypeB();
return Arrays.asList(subTypeB.getPropertyA(), subTypeB.getPropertyB());
}))
.collect(Collectors.toList());
Note: This relies on the assumption as stated in the question that all the subtypes are possible to cast without an instanceof
check.
Upvotes: 1
Reputation: 1679
Is it possible for you to override
equals
and hashCode
method for the types TypeA
and SubTypeB
?
If yes, this is fairly straightforward. If no, I will edit this answer accordingly.
class TypeA {
private SuperTypeB superTypeB;
public SuperTypeB getSuperTypeB(){ return superTypeB; }
@Override
public boolean equals( final Object o) {
if (this == o) return true;
if (!(o instanceof TypeA)) return false;
TypeA typeA = (TypeA) o;
return superTypeB.equals(typeA.superTypeB);
}
@Override
public int hashCode() {
return Objects.hash(superTypeB);
}
}
class SubTypeB extends SuperTypeB {
private String propertyA;
private String propertyB;
public String getPropertyA(){ return propertyA; }
public String getPropertyB(){ return propertyB; }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof SubTypeB)) return false;
SubTypeB subTypeB = (SubTypeB) o;
return propertyA.equals(subTypeB.propertyA) &&
propertyB.equals(subTypeB.propertyB);
}
@Override
public int hashCode() {
return Objects.hash(propertyA, propertyB);
}
}
After this, all you need to do is this:
List<TypeA> finalList = list.stream().distinct().collect(Collectors.toList());
The only assurance that you can get in the stream API that you will get the first occurrence of each distinct object is through the order in which the stream emits objects. Otherwise, you have no control over which element you encounter first.
Upvotes: 0