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

2
  • 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) Commented Aug 12, 2019 at 15:50
  • 1
    I think you are looking for this (see section 1.2) mkyong.com/java8/… Commented Aug 12, 2019 at 15:50

2 Answers 2

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

Sign up to request clarification or add additional context in comments.

1 Comment

Instead of .map(ComponentErrorDetail::getComponentCode) .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())), you can simply use .collect(Collectors.groupingBy(ComponentErrorDetail::getComponentCode, Collectors.counting()))
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());
;

6 Comments

forEachOrdered is a terminal operation - this will throw when you try to call entrySet the second time.
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 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 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 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.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.