Just curious to know on whether we can sort a List according to the frequency of repeated numbers using Java 8 without writing a Custom Comparator class.
I need to sort the given integers based on its frequency and then by the natural numerical order.
I'm getting error at Comparator.naturalOrder();
Here is the code which I tried:
Integer[] given = new Integer[]{0,0,1,22,11,22,22,11,44,555,55,66,77,88,99};
List<Integer> intList = Arrays.asList(given);
Map<Integer, Long> frequencyMap = intList.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
List<Integer> newList = intList.stream().sorted(Comparator.comparing(frequencyMap::get).thenComparing(Comparator.naturalOrder())).collect(Collectors.toList());
System.out.println(newList.toString());
The expected output is
[1, 44, 55, 66, 77, 88, 99, 555, 0, 0, 11, 11, 22, 22, 22]
PS: Used arrays in first line in order to avoid list.add() in multiple lines and for clear understanding.
Unfortunately, Java's type inference can't recognize the type of the compared object when chaining Comparator.comparing(frequencyMap::get)
with thenComparing(Comparator.naturalOrder())
. Since the method signature of Map.get
is get(Object)
, the compiler infers Comparator<Object>
as result type of Comparator.comparing(frequencyMap::get)
.
You can fix this by inserting an explicit type. But note that you are not using the result of collect(Collectors.toList())
but just printing the original, unaffected List
. On the other hand, you don't need the List
when the array is given:
Integer[] given = {0,0,1,22,11,22,22,11,44,555,55,66,77,88,99};
Map<Integer, Long> frequencyMap = Arrays.stream(given)
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
Arrays.sort(given,
Comparator.<Integer>comparingLong(frequencyMap::get)
.thenComparing(Comparator.naturalOrder()));
System.out.println(Arrays.toString(given));
For printing without changing the array you can also use the following alternative
Arrays.stream(given)
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet().stream()
.sorted(Map.Entry.<Integer, Long>comparingByValue()
.thenComparing(Map.Entry.comparingByKey()))
.flatMap(e -> LongStream.range(0, e.getValue()).mapToObj(l -> e.getKey()))
.forEach(System.out::println);
This sorts the groups instead of the individual values and prints identical values as often as they've been counted.
you need to add a type witness, minor compiler weakness:
intList.stream()
.sorted(Comparator.comparing((Integer x) -> frequencyMap.get(x))
.thenComparing(Comparator.naturalOrder()))
.forEachOrdered(System.out::println);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.