Reputation: 488
I have a list of objects. Each object has three fields: id
, secNumber
and type
. Type
is enum which can have values 'new'
or 'legacy'
. Sometimes it happens that there are objects in that list which have the same secNumber
a but different type.
in such a situation, I need to remove the one with type 'legacy'. How to do it using Java 8 streams?
Upvotes: 0
Views: 2474
Reputation: 56393
use toMap
with something like this:
Collection<T> result = list.stream()
.collect(toMap(T::getSecNumber,
Function.identity(),
(l, r) -> l.getType() == Type.LEGACY ? r : l))
.values();
where T
is the class that contains secNumber
, id
etc.
keyMapper
(T::getSecNumber
) extracts each secNumber
from each object.valueMapper
(Function.identity()
) extracts the objects we want as the map values i.e. the objects from the source them selves.mergeFunction
(l, r) ->
is where we say " if two given objects have the same key i.e. getSecNumber
then keep the one where their type is 'NEW' and discard the one with 'LEGACY'" and finally we call values()
to accumulate the map values into a Collection.Edit:
following @Tomer Aberbach's comment you may be looking for:
List<T> result =
list.stream()
.collect(groupingBy(T::getSecNumber))
.values()
.stream()
.flatMap(l -> l.stream().anyMatch(e -> e.getType() == Type.NEW) ?
l.stream().filter(e -> e.getType() != Type.LEGACY) :
l.stream())
.collect(toList());
The first solution using toMap
assumes there can't be multiple objects with the same secNumber
and type
.
Upvotes: 3
Reputation: 646
Assume objects
is a List<ClassName>
which has been declared and initialized:
List<ClassName> filteredObjects = objects.stream()
.collect(Collectors.groupingBy(ClassName::getSecNumber))
.values().stream()
.flatMap(os -> os.stream().anyMatch(o -> o.getType() == Type.NEW) ?
os.stream().filter(o -> o.getType() != Type.LEGACY) :
os.stream()
).collect(Collectors.toList());
I made the assumption that objects of type Type.LEGACY
should only be filtered out if there exists another object of type Type.NEW
which has the same secNumber
. I also made the assumption that you could have multiple objects of the same type
and secNumber
and that those may need to be retained.
Note that the collect(Collectors.groupingBy(ClassName::getSecNumber))
returns a map from whatever type secNumber
is to List<ClassName>
so calling values()
on it returns a Collection<List<ClassName>>
which represents a collection of the groupings of objects with the same secNumber
.
The flatMap
part takes each grouping by secNumber
, checks if the grouping has at least one object of Type.NEW
, and if so, filters out the objects of type Type.LEGACY
, otherwise it just passes along the objects to be flattened into the final List<ClassName>
. This is primarily so that if a grouping only has objects of type Type.LEGACY
then they are not left out of the final collection.
Upvotes: 3