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

Related searches

I've tested a bit the max function on Java 8 lambdas and streams, and it seems that in case max is executed, even if more than one object compares to 0, it returns an arbitrary element within the tied candidates without further consideration.

Is there an evident trick or function for such a max expected behavior, so that all max values are returned? I don't see anything in the API but I am sure it must exist something better than comparing manually.

For instance:

// myComparator is an IntegerComparator
Stream.of(1, 3, 5, 3, 2, 3, 5)
    .max(myComparator)
    .forEach(System.out::println);
// Would print 5, 5 in any order.

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

Finding Max/Min of a List or Collection, Getting object with min/max value property from list of objects in Java 8, Output :. How to force max to return ALL maximum values in a Java Stream , Writing� Last Updated: 06-12-2018 Stream.max () returns the maximum element of the stream based on the provided Comparator. A Comparator is a comparison function, which imposes a total ordering on some collection of objects. max () is a terminal operation which combines stream elements and returns a summary result.

I believe the OP is using a Comparator to partition the input into equivalence classes, and the desired result is a list of members of the equivalence class that is the maximum according to that Comparator.

Unfortunately, using int values as a sample problem is a terrible example. All equal int values are fungible, so there is no notion of preserving the ordering of equivalent values. Perhaps a better example is using string lengths, where the desired result is to return a list of strings from an input that all have the longest length within that input.

I don't know of any way to do this without storing at least partial results in a collection.

Given an input collection, say

List<String> list = ... ;

...it's simple enough to do this in two passes, the first to get the longest length, and the second to filter the strings that have that length:

int longest = list.stream()
                  .mapToInt(String::length)
                  .max()
                  .orElse(-1);

List<String> result = list.stream()
                          .filter(s -> s.length() == longest)
                          .collect(toList());

If the input is a stream, which cannot be traversed more than once, it is possible to compute the result in only a single pass using a collector. Writing such a collector isn't difficult, but it is a bit tedious as there are several cases to be handled. A helper function that generates such a collector, given a Comparator, is as follows:

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;
            }
        });
}

This stores intermediate results in an ArrayList. The invariant is that all elements within any such list are equivalent in terms of the Comparator. When adding an element, if it's less than the elements in the list, it's ignored; if it's equal, it's added; and if it's greater, the list is emptied and the new element is added. Merging isn't too difficult either: the list with the greater elements is returned, but if their elements are equal the lists are appended.

Given an input stream, this is pretty easy to use:

Stream<String> input = ... ;

List<String> result = input.collect(maxList(comparing(String::length)));

Java 8 filter List by highest values of each id, java get max value from list of objects find max value in hashmap java 8 discussed in “How to force max() to return ALL maximum values in a Java Stream ? 1. Stream.max() method Optional<T> max(Comparator<? super T> comparator) This is a terminal operation. So stream cannot be used after this method is executed. Returns the maximum/largest element of this stream according to the provided Comparator. This is a special case of a stream reduction.

I implemented more generic collector solution with custom downstream collector. Probably some readers might find it useful:

public static <T, A, D> Collector<T, ?, D> maxAll(Comparator<? super T> comparator, 
                                                  Collector<? super T, A, D> downstream) {
    Supplier<A> downstreamSupplier = downstream.supplier();
    BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
    BinaryOperator<A> downstreamCombiner = downstream.combiner();
    class Container {
        A acc;
        T obj;
        boolean hasAny;

        Container(A acc) {
            this.acc = acc;
        }
    }
    Supplier<Container> supplier = () -> new Container(downstreamSupplier.get());
    BiConsumer<Container, T> accumulator = (acc, t) -> {
        if(!acc.hasAny) {
            downstreamAccumulator.accept(acc.acc, t);
            acc.obj = t;
            acc.hasAny = true;
        } else {
            int cmp = comparator.compare(t, acc.obj);
            if (cmp > 0) {
                acc.acc = downstreamSupplier.get();
                acc.obj = t;
            }
            if (cmp >= 0)
                downstreamAccumulator.accept(acc.acc, t);
        }
    };
    BinaryOperator<Container> combiner = (acc1, acc2) -> {
        if (!acc2.hasAny) {
            return acc1;
        }
        if (!acc1.hasAny) {
            return acc2;
        }
        int cmp = comparator.compare(acc1.obj, acc2.obj);
        if (cmp > 0) {
            return acc1;
        }
        if (cmp < 0) {
            return acc2;
        }
        acc1.acc = downstreamCombiner.apply(acc1.acc, acc2.acc);
        return acc1;
    };
    Function<Container, D> finisher = acc -> downstream.finisher().apply(acc.acc);
    return Collector.of(supplier, accumulator, combiner, finisher);
}

So by default it can be collected to list:

public static <T> Collector<T, ?, List<T>> maxAll(Comparator<? super T> comparator) {
    return maxAll(comparator, Collectors.toList());
}

But you can use other downstream collectors as well:

public static String joinLongestStrings(Collection<String> input) {
    return input.stream().collect(
            maxAll(Comparator.comparingInt(String::length), Collectors.joining(","))));
}

how to find maximum value from a Integer using stream in java 8?, Stream.max() returns the maximum element of the stream based on the provided Comparator. Exception : This method throws NullPointerException if the maximum element is null. System.out.print( "The maximum value is : " ); Get hold of all the important DSA concepts with the DSA Self Paced� Java 8 Stream min () and max () By Yashwant Chavan, Views 118150, Last updated on 03-Nov-2016. In this tutorial you will learn about min () and max () methods which returns an Optional instance. To obtain the value from Optional instance use get () method. It will return null value if stream has no elements. The min () and max () methods take a Comparator as a input parameter which compares the values using Comparator.comparing () method.

If I understood well, you want the frequency of the max value in the Stream.

One way to achieve that would be to store the results in a TreeMap<Integer, List<Integer> when you collect elements from the Stream. Then you grab the last key (or first depending on the comparator you give) to get the value which will contains the list of max values.

List<Integer> maxValues = st.collect(toMap(i -> i,
                     Arrays::asList,
                     (l1, l2) -> Stream.concat(l1.stream(), l2.stream()).collect(toList()),
                     TreeMap::new))
             .lastEntry()
             .getValue();

Collecting it from the Stream(4, 5, -2, 5, 5) will give you a List [5, 5, 5].

Another approach in the same spirit would be to use a group by operation combined with the counting() collector:

Entry<Integer, Long> maxValues = st.collect(groupingBy(i -> i,
                TreeMap::new,
                counting())).lastEntry(); //5=3 -> 5 appears 3 times

Basically you firstly get a Map<Integer, List<Integer>>. Then the downstream counting() collector will return the number of elements in each list mapped by its key resulting in a Map. From there you grab the max entry.

The first approaches require to store all the elements from the stream. The second one is better (see Holger's comment) as the intermediate List is not built. In both approached, the result is computed in a single pass.

If you get the source from a collection, you may want to use Collections.max one time to find the maximum value followed by Collections.frequency to find how many times this value appears.

It requires two passes but uses less memory as you don't have to build the data-structure.

The stream equivalent would be coll.stream().max(...).get(...) followed by coll.stream().filter(...).count().

Stream.max() method in Java with Examples, Returns the maximum element of the given collection, according to the natural Replaces all occurrences of one specified value in a list with another. public static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp) This implementation uses the "brute force" technique of scanning over the source � To get max or min date from a stream of dates, you can use Comparator.comparing ( LocalDate::toEpochDay ) comparator. toEpochDay () function simply increment count of days for a date where day 0 is for 1970-01-01. Find max or min date from list of dates. LocalDate start = LocalDate.now ();

Collections (Java Platform SE 8 ), Find the minimum and maximum values in a list without using Stream : To find the minimum and maximum values in a list, first take the inputs from the user. Create two variables ’max’ and ’min’ to store the maximum and minimum value in the list. Assign both the first number of the list. Now iterate through the list one by one. Check for each element: if the element is greater than current max value, set it as max.

The idea is to convert the list of objects into a Stream of objects and then use Stream#max () method that accepts a Comparator to compare objects based on a field value and returns an Optional containing the maximum object in the stream. Similarly, for finding the minimum object in the stream, we can use Stream#min () function.

The idea is to convert the list to IntStream and use max () method provided by IntStream that returns an OptionalInt containing the maximum element of the stream. In order to unwrap an OptionalInt and get a hold of real Integer inside, we can either use orElseThrow or orElse or orElseGet.

In this quick tutorial, we'll explore various ways to find the maximum value in a Java Map. We'll also see how new features in Java 8 have simplified this operation. Before we begin let's briefly recap how objects are compared in Java.

Comments
  • What exactly do you want this max method to return? A HashSet?
  • A hashset or a way to chain more operations as if it was a filter, with the tied maxes
  • Your statement is incorrect. If the stream is ordered (such as the streams you get from an array or List), it returns the first element that is maximal in the event of multiple maximal elements; only if the stream is unordered is it allowed to pick an arbitrary element.
  • thanks for the point, I didn't think of
  • Great answer. Writing your own collectors is really powerful and actually quite straightforward, once you get your head around the supplier/accumulator/combiner/finisher nomenclature!
  • "Both approaches require to store all the elements from the stream" that’s a misleading statement considering that the second approach stores only counts rather than lists of elements. That’s the whole point of providing another Collector rather than creating a Map<…, List…> first. It has to process every item but will not store the items.
  • @Holger Thanks, I don't know why I assumed that.
  • yes, it is getting the max occurences (not index) given a comparator (which does not have any tie breaking system). Preferrably in a stream fashion (i mean the output is a stream of those max elements, like if it was a filter, not a collector or a ending operation)
  • @user1352530 I think you're asking the wrong question. People used to ask "how can I do X?". Now they ask "how can I do X using streams?". It's the wrong question. The objective is to do X, not to use streams.
  • I am just learning the approaches, not a real need. I could workaround it, but I'm sure there must be a efficient or shortcut for this. Also, take a look at the post update
  • @user1352530: you can’t single-pass stream like a filter operation as you have to process every element including the last one before you definitely know what the max element is. Just consider the possibility that the very last element is the sole maximum value. Even if you find a way to hide this fact in something that looks like a single stream operation (like with Stream.sorted) it will imply processing/collecting all element before a downstream operation can take place.