2

I have a list of integers, and would like to print all their elements in a sorted way, by 2 properties: list size and the sum of the elements on the list. I read on streams thenComparing method, but an error shows up whenever I try to use it.

I wrote some code that is working, but would like to know if there is any other cleaner way to do it. Thanks in advance!

Map<List<Integer>, Double> entropies = new HashMap<>();

// Extra code removed

entropies.keySet()
    .stream().sorted(Comparator.comparingInt(o -> {
        List<Integer> a = (List<Integer>) o;
        return a.size();
    }).thenComparingInt(o -> {
        List<Integer> a = (List<Integer>) o;
        return a.stream().mapToInt(Integer::intValue).sum();
    }))
    .forEach(key -> logger.debug("{} => {}", key, entropies.get(key)));

Same as actual output but without castings would be great.

Neel Patel
  • 143
  • 12

1 Answers1

3

The following should work:

entropies.keySet()
         .stream().sorted(Comparator.<List<Integer>>comparingInt(List::size)
                              .thenComparingInt(o -> o.stream().mapToInt(Integer::intValue).sum()))
         .forEach(key -> logger.debug("{} => {}", key, entropies.get(key)));

Since Comparator.comparingInt is not able to infer the type as List>. The type hint when you call let's the compiler know the actual type. This is because the sorted method expects Comparator<? super List<Integer>> comparator, so technically your comparator could have any superclass of List, so you need to explicitly specify which superclass it is.

Hari Menon
  • 33,649
  • 14
  • 85
  • 108
  • Nice summary for why having to add the type hint; further details at https://stackoverflow.com/questions/24794924/generic-type-inference-not-working-with-method-chaining . Also a second option is to use `o -> o.stream().collect(Collectors.summingInt(i->i))` – racraman Jun 05 '19 at 01:45
  • Thanks, I got it working. But more than that, you provided a explanation on why what I tried to do didn't work and what I needed to change. Also, thanks to racraman to provide more details on this and on that second option. – José Coelho Jun 05 '19 at 08:32
  • You can also use the slightly simpler `Comparator.comparingInt(List::size) .thenComparingInt(l -> l.stream().mapToInt(Integer::intValue).sum())` Also, an explicitely typed lambda expression would work: `Comparator.comparingInt((List l) -> l.size()) .thenComparingInt(l -> l.stream().mapToInt(Integer::intValue).sum())` – Holger Jun 05 '19 at 10:57