2

Using a stream, how to sort a list of objects by field (in my case ,componentCode) that has the maximum number of duplicates, and then find distinct

I tried something like this, but how to add the size of the duplicates when sorting.

List<String> conflictingComponentsCode = componentWarnings.stream()
    .sorted(Comparator.comparing(ComponentErrorDetail::getComponentCode))
    .map(ComponentErrorDetail::getComponentCode)
    .distinct()
    .collect(Collectors.toList());

enter image description here

Stefan Zobel
  • 3,182
  • 7
  • 28
  • 38
Jay
  • 9,189
  • 12
  • 56
  • 96
  • 3
    Could you please replace your (largely unhelpful) screenshot with simple data examples entered as text, and eliminate irrlelevant fields (such as "concentration", "errorDesc", etc) – Bohemian Aug 12 '19 at 15:50
  • 1
    I think you are looking for this (see section 1.2) https://www.mkyong.com/java8/java-8-collectors-groupingby-and-mapping-example/ – nafas Aug 12 '19 at 15:50

2 Answers2

4

Very similar to @nafas option:

List<String> conflictingComponentsCode = componentWarnings.stream()
    .map(ComponentErrorDetail::getComponentCode)
    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())) 
    .entrySet()
    .stream()
    .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
    .map(Map.Entry::getKey)
    .collect(Collectors.toList());

You can check this question for another example of grouping by count: Group by counting in Java 8 stream API

Naman
  • 27,789
  • 26
  • 218
  • 353
Anne
  • 219
  • 2
  • 8
  • 2
    Instead of `.map(ComponentErrorDetail::getComponentCode) .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))`, you can simply use `.collect(Collectors.groupingBy(ComponentErrorDetail::getComponentCode, Collectors.counting()))` – Holger Aug 13 '19 at 10:09
2

the idea is to use Collectors.groupingBy function to make a map (value to count), then sort the map in reverse order then map back to list again.

here a rough implementation:

List<String> conflictingComponentsCode = 
componentWarnings.stream()
    .map(ComponentErrorDetail::getComponentCode).collect(
        Collectors.groupingBy(
            Function.identity(), Collectors.counting())
        ) 
    //sort map
    .entrySet().stream()
        .sorted(Map.Entry.<String, Long>comparingByValue()
             .reversed())

    //map to list
   .map(entry -> entry.key()).collect(Collectors.toList());
;
nafas
  • 5,283
  • 3
  • 29
  • 57
  • 2
    [forEachOrdered](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#forEachOrdered-java.util.function.Consumer-) is a [terminal operation](https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#StreamOps) - this will throw when you try to call `entrySet` the second time. – Avi Aug 12 '19 at 16:03
  • Actually, the problem isn't that it's a terminal operation (`collect(...)` is too and that's fine), the problem is that `forEachOrdered(...)` has a **`void`** return type. – Andreas Aug 12 '19 at 16:20
  • @Andreas `collect` returns a value - the reason it seems ok here is that all further operations are called on the return value. In truth, the stream generated by `componentWarnings::stream` can no longer be operated on, the moment that `collect` is called. – Avi Aug 12 '19 at 16:24
  • 1
    @Avi I know. My point is that the issue with this code is not that `forEachOrdered` is *terminal*, but that it is `void`. I used `collect` as an example that a terminal operation is fine in a method chain like this. It's having a `void` method that breaks the chain, not having a *terminal* operation. – Andreas Aug 12 '19 at 16:32
  • @Andreas the problem with this code is the `void` return type of `forEachOrdered` **and** the `finalMap` appearing out of nowhere. Besides the point that this collecting this sorted stream into a map, just to stream again over it, before collecting into the final list, is entirely obsolete. – Holger Aug 13 '19 at 10:15
  • thanks, guys, that's what happens when I don't run my codes. I think its fixed now – nafas Aug 13 '19 at 13:43