Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write a mode method using streams

I am trying to write a method to get the mode of a Collection using a Comparator.

Please can somebody show me what changes I have to make to get this to compile? I do not want to change the signature.

static <T> T mode(Collection<? extends T> collection, Comparator<? super T> comparator) {
    return collection.stream()
                     .collect(Collectors.groupingBy(t -> t, () -> new TreeMap<>(comparator), Collectors.counting()))
                     .entrySet()
                     .stream()
                     .reduce(BinaryOperator.maxBy(Comparator.comparingLong(Map.Entry::getValue)))
                     .map(Map.Entry::getKey)
                     .orElseThrow(IllegalArgumentException::new);
}

EDIT

It turns out I was just using the wrong version. This does not compile using javac 1.8.0_25. The exact three error messages are:

Error:(40, 47) java: incompatible types: inferred type does not conform to upper bound(s)
inferred: java.lang.Object
upper bound(s): T,java.lang.Object

Error:(43, 45) java: incompatible types: cannot infer type-variable(s) T
(argument mismatch; invalid method reference
  method getValue in interface java.util.Map.Entry<K,V> cannot be applied to given types
    required: no arguments
    found: java.lang.Object
    reason: actual and formal argument lists differ in length)

Error:(44, 25) java: invalid method reference
non-static method getKey() cannot be referenced from a static context

However, I have since upgraded to javac 1.8.0_65 and it compiles perfectly.

like image 796
Paul Boddington Avatar asked Sep 26 '22 02:09

Paul Boddington


1 Answers

This code does not compile with javac prior to Java 8u40. If you still want to make it compatible with older javac versions, you can introduce another generic variable like this:

static <T> T mode(Collection<? extends T> collection, Comparator<? super T> comparator) {
    return mode0(collection, comparator);
}

private static <T, TT extends T> T mode0(Collection<TT> collection,
                                         Comparator<? super T> comparator) {
    return collection.stream()
                     .collect(Collectors.groupingBy(t -> t, 
                                  () -> new TreeMap<>(comparator), 
                                  Collectors.counting()))
                     .entrySet()
                     .stream()
                     .reduce(BinaryOperator.maxBy(
                                  Comparator.comparingLong(Map.Entry::getValue)))
                     .map(Map.Entry::getKey)
                     .orElseThrow(IllegalArgumentException::new);
}

By the way you may use Stream.max instead of reduce and Map.Entry.comparingByValue() comparator:

private static <T, TT extends T> T mode0(Collection<TT> collection,
                                         Comparator<? super T> comparator) {
    return collection.stream()
                     .collect(Collectors.groupingBy(t -> t, 
                                  () -> new TreeMap<>(comparator), 
                                  Collectors.counting()))
                     .entrySet()
                     .stream()
                     .max(Map.Entry.comparingByValue())
                     .map(Map.Entry::getKey)
                     .orElseThrow(IllegalArgumentException::new);
}
like image 113
Tagir Valeev Avatar answered Sep 29 '22 08:09

Tagir Valeev