I have a Stream
of custom objects as a parameter to a method. And obviously I can consume the Stream only once.
My object has a String
attribute called category
.
public class MyType {
private String category;
// other properties, getters, etc.
}
I need a sorted list of categories List<String>
.
First, I need to sort the data based on the number of occurrences of each category. If the number of occurrences is the same, then sort such categories lexicographically.
Basically, I need something like this
java8 stream grouping and sorting on aggregate sum
but I don't have the luxury of consuming the stream more than once. So I don't know how to address this problem.
Here's an example:
Input:
{
object1 :{category:"category1"},
object2 :{category:"categoryB"},
object3 :{category:"categoryA"},
object4 :{category:"category1"},
object5 :{category:"categoryB"},
object6 :{category:"category1"},
object7 :{category:"categoryA"}
}
Output:
List = {category1, categoryA, categoryB}
CodePudding user response:
You can generate a Map of frequencies for each category of type Map<String,Long>
(count by category).
Then create a stream over its entries and sort them (by Value, i.e. by count, and Key, i.e. lexicographically), extract the category from each entry and store the result into a list.
Assuming that you have the following domain type:
public class MyType {
private String category;
// getters
}
Method generating a sorted list of categories might be implemented like this:
public static List<String> getSortedCategories(Stream<MyType> stream) {
return stream.collect(Collectors.groupingBy(
MyType::getCategory,
Collectors.counting()
))
.entrySet().stream()
.sorted(
Map.Entry.<String, Long>comparingByValue()
.thenComparing(Map.Entry.comparingByKey())
)
.map(Map.Entry::getKey)
.toList();
}