How to Force Max to Return All Maximum Values in a Java Stream

How to force max to return ALL maximum values in a Java Stream?

I would group by value and store the values into a TreeMap in order to have my values sorted, then I would get the max value by getting the last entry as next:

Stream.of(1, 3, 5, 3, 2, 3, 5)
.collect(groupingBy(Function.identity(), TreeMap::new, toList()))
.lastEntry()
.getValue()
.forEach(System.out::println);

Output:

5
5

How to get all objects having the same max value with Java streams?

You could collect to a TreeMap first and only get the last entry (where the max is)

players.stream()
.collect(Collectors.groupingBy(
Player::getPoints,
TreeMap::new,
Collectors.toList()
))
.lastEntry()
.getValue();

How to get all elements with the highest value with Java streams?

You can do this using a TreeMap and the Collectors.groupingBy():

TreeMap<Integer, List<MyPojo>> map = pojos.stream()
.collect(Collectors.groupingBy(
MyPojo::getPriority,
TreeMap::new,
Collectors.toList()
));

List<MyPojo> maxPrios = map.lastEntry().getValue();

The lastEntry() will return the pojos with the highest priority, due to the natural ordering of Integers where the smallest value will be first, and the largest value will be last.

Collect objects with max value in a list with streams

I did something like this. I group by the score and then find the score with maximum key value. It will return an Optional of Map.Entry. It contains both the maximum value and the players that have it. Then I can get the list of players using getValue() method.

List<Player> value = playerList.stream()
.collect(groupingBy(Player::getScore))
.entrySet()
.stream()
.max(Comparator.comparing(Map.Entry::getKey))
.get()
.getValue();

How can I filter stream by some max value from it?

If you have to do in one pass, you can write a custom Collector to reduce the stream into a list of max elements. Here's an implementation based on this answer by Stuart Marks.

List<MyObject> maxList = list.stream()
.collect(maxList(Comparator.comparing(MyObject::getSome)));

static <T> Collector<T,?,List<T>> maxList(Comparator<? super T> comp) {
return Collector.of(
ArrayList::new,
(list, t) -> {
int c;
if (list.isEmpty() || (c = comp.compare(t, list.get(0))) == 0) {
list.add(t);
} else if (c > 0) {
list.clear();
list.add(t);
}
},
(list1, list2) -> {
if (list1.isEmpty()) {
return list2;
}
if (list2.isEmpty()) {
return list1;
}
int r = comp.compare(list1.get(0), list2.get(0));
if (r < 0) {
return list2;
} else if (r > 0) {
return list1;
} else {
list1.addAll(list2);
return list1;
}
});
}

The Collector will maintain an ArrayList to be used for the result, and accumulate each element into it, checking how the element compares to the first element of the current list. The part c = comp.compare(t, list.get(0))) == 0 will check if the element has the same max value, and if so will add it to the list.

Using Java8 Stream to find the highest values from map

You can get a single key via

Integer max=mapGroup.entrySet().stream().max(Map.Entry.comparingByValue()).get().getKey();

but unfortunately, there is no built-in function for getting all equivalent maximums.

The simplest, straight-forward solution is to find the maximum value first and retrieve all keys mapping to that value afterwards:

private List<Integer> testStreamMap(Map<Integer, Long> mapGroup) {
if(mapGroup.isEmpty())
return Collections.emptyList();
long max = mapGroup.values().stream().max(Comparator.naturalOrder()).get();
return mapGroup.entrySet().stream()
.filter(e -> e.getValue() == max)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
}

Solutions for getting all maximum values of a stream in a single pass, are discussed in “How to force max() to return ALL maximum values in a Java Stream?”. You will see that single-pass solutions are much more complicated and not worth the effort if your input is an ordinary Map (e.g. HashMap), which can be iterated multiple times cheaply.

Get a list of object with max values

IF you want a single pipeline, you can group the Students by that property, and if you produce a TreeMap for the output, it will be sorted, so you'll have access to the Set corresponding with the max value:

return
this.students()
.stream()
.collect(Collectors.groupingBy(student -> student.getAssignedProjects().size(),
TreeMap::new,
Collectors.toSet()))
.lastEntry()
.getValue();

Of course, if the number of Students having the max value is small relative to the size of the input list, it would be inefficient to sort the grouped Students (which is what creating a TreeMap would do). Your original code would be more efficient.

How to get the max by key of the result of groupingBy

There are several ways to get a map entry by max key:

  1. Use sorted map like TreeMap and then get use lastEntry method:
TreeMap<Integer, List<Alien>> map =  aliens.stream()
.filter(x -> x.pos[1] == SpaceInvaders.ship)
.collect(Collectors.groupingBy(
x -> x.pos[0], TreeMap::new, Collectors.toList()
));
System.out.println(map.lastEntry());

  1. (by Holger's comment) Use Stream::max returning Optional result
aliens.stream()
.filter(x -> x.pos[1] == SpaceInvaders.ship)
.collect(Collectors.groupingBy(x -> x.pos[0])) // non-sorted map
.entrySet()
.stream()
.max(Map.Entry.comparingByKey()) // returns Optional<Map.Entry>
.ifPresent(System.out::println); // print entry with max key if available

  1. Sort entries of the aliens by key in reverse order and pick up only one entry:
aliens.stream()
.filter(x -> x.pos[1] == SpaceInvaders.ship)
.collect(Collectors.groupingBy(x -> x.pos[0])) // non-sorted map
.entrySet()
.stream()
.sorted(Map.Entry.<Integer, List<Alien>>comparingByKey().reversed())
.limit(1)
.forEach(System.out::println);

java 8 get elements with equal max number of occurences

In the first place, why do you start with a Stream<Character>. You can start with an array of chars and then use the iteration to build up a map from char to count and in the meantime calculate the max value in the map while iterating. Then use this map and the max value intermediate result to get the final result. This approach just passes over the collection only twice. Here's how it looks given that you have a char[] named chars upfront.

final Map<Character, Integer> charCntMap = new HashMap<>();
int maxCnt = 0;
for (char c : chars) {
charCntMap.merge(c, 1, (a, b) -> a + b);
final int charCnt = charCntMap.get(c);
if (maxCnt < charCnt)
maxCnt = charCnt;
}

final int maxVal = maxCnt;

List<Character> maxOccuringChars = charCntMap.entrySet().stream()
.filter(e -> e.getValue().intValue() == maxVal)
.map(Map.Entry::getKey)
.collect(Collectors.toList());

Output:

[A, B]


Related Topics



Leave a reply



Submit