Given the following example class:
class Foo{
String name;
int value;
public Foo(String name, int value) {
this.name = name;
this.value = value;
}
// getters, setters, toString & equals
}
and a list of foos:
List<Foo> fooList = List.of(new Foo("A",1), new Foo("A",2),
new Foo("B",1),
new Foo("C",1),
new Foo("D",1), new Foo("D",2), new Foo("D",3)
);
I want to get a list of foos distinct by name and if there are more than one Foos
I want to keep the one with the highst value.
I've found this java-8-distinct-by-property question to get elemnts of the list distinct by name, which uses this method to get distinct elements:
public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
Set<Object> seen = ConcurrentHashMap.newKeySet();
return t -> seen.add(keyExtractor.apply(t));
}
I use it like:
fooList.stream().filter(distinctByKey(Foo::getName)).collect(Collectors.toList());
It works to get distinct elements but keeps the first element in the list if there are two or more with the same name and I'am not able to add a condition to keep the one with the highst value.
Another option is to use grouping by:
Map<String,List<Foo>> map = fooList.stream().collect(Collectors.groupingBy(f -> f.getName()));
Here I don't know how to collect the Foos with the highst value from the map to a list.
With the first approach I get:
Foo{name=A, value=1}
Foo{name=B, value=1}
Foo{name=C, value=1}
Foo{name=D, value=1}
With the second:
A=[Foo{name=A, value=1}, Foo{name=A, value=2}]
B=[Foo{name=B, value=1}]
C=[Foo{name=C, value=1}]
D=[Foo{name=D, value=1}, Foo{name=D, value=2}, Foo{name=D, value=3}]
How can I get a list of:
Foo{name=A, value=2}
Foo{name=B, value=1}
Foo{name=C, value=1}
Foo{name=D, value=3}