How can one get the distinct (distinct based on two property) list from a list of objects.
for example let there are list of objects with property name and price.
Now how can I get a list with distinct name or price.
suppose
list<xyz> l1 = getlist(); // getlist will return the list.
Now let l1 has the following properties(name, price) :-
n1, p1
n1, p2
n2, p1
n2, p3
Now after the filter the list should be-
n1, p1
n2, p3
I tried solving like this -
public List<xyz> getFilteredList(List<xyz> l1) {
return l1
.stream()
.filter(distinctByKey(xyz::getName))
.filter(distinctByKey(xyz::getPrice))
.collect(Collectors.toList());
}
private static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
Map<Object,Boolean> seen = new ConcurrentHashMap<>();
return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
Now the problem is when i did filter on name the list return would be -
n1, p1
n2, p1
and then it would have run filter on price which return -
n1, p1
which is not the expected result.
Almost verbatim from Stuart Marks' answer:
This main method yields:
Edit
Made price an
int
per Eugene's prompting.Note: that you could use something more interesting as a key if you wanted to flesh it out:
I'd go for something like this, which is fairly simple and flexible, and builds on your example:
This can then be called in the following manner:
Here is my solution based on the class
Item
which defines aname
and aprice
:The requirement is to obtain only
Item
s from a givenList<Item>
which have distinctname
s and distinctprice
s, in the order in which they occur.I catch this requirement of being distinct by a class
ItemWrapper
:Now we have everything in place to filter a given
List<Item>
of items:as following:
The items captured are: