使用Java 8 Stream API进行计数和排序

我想知道如何通过COUNT然后ASC订购。

Stream fruits = Stream.of("apple", "orange", "ananas"); Map letters = fruits.map(w -> w.split("")) .flatMap(Arrays::stream) .collect(groupingBy(identity(), counting())); 

输出:

 {p=2, a=5, r=1, s=1, e=2, g=1, l=1, n=3, o=1}` 

期望的输出:

 {a=5, n=3, e=2, p=2, g=1, l=1, r=1, s=1, o=1} 

在您根据计数进行排序之前,首先需要计数,这在两个映射步骤中是不可避免的:

 Map letters = fruits .flatMap(Pattern.compile("")::splitAsStream) .collect(groupingBy(identity(), counting())) .entrySet().stream().sorted(Map.Entry.comparingByValue(reverseOrder())) .collect(LinkedHashMap::new, (m,e) -> m.put(e.getKey(), e.getValue()), Map::putAll); 

如果您假设只有ASCII小写字母(或任何其他小的固定大小的字符集),您可以尝试一种可能更有效的替代方法。 它将处理字符并计为原始值,存储在固定大小的数组中。 仅为最终排序和Map生成生成对象:

 long[] histogram=fruits.flatMapToInt(String::chars) .filter(c -> c>='a' && c<='z')// just to be sure, remove if you prefer exceptions .collect(()->new long[26],(a,c)->a[c-'a']++, (a,b)->Arrays.setAll(a, ix->a[ix]+b[ix])); Map letters=IntStream.range(0, 26).filter(i->histogram[i]!=0) .boxed().sorted(comparingLong(i -> -histogram[i])) .collect(LinkedHashMap::new, (m,i)->m.put(""+(char)(i+'a'),histogram[i]), Map::putAll); 

您无法按其值排序地图。 我认为您可以实现的最好的方法是将已排序的条目存储到LinkedHashMap中,这样当您迭代其他条件时,您将获得预期的结果(因为您将按所需的排序顺序添加映射)。

为此,您需要按操作的第一组来了解如何构建映射’Letter – > occurrence’(您可能还会考虑Map )。

然后,您必须再次迭代条目集,并对流进行排序,以便条目首先按其值排序,然后按键的自然顺序排序。 所以比较器看起来像:

 //need to provide explicit type parameters due to limited type inference at the moment Comparator> cmp = Map.Entry.comparingByValue(reverseOrder()).thenComparing(Map.Entry.comparingByKey()); 

将所有部分放在一起,它产生:

 Map letters = fruits.flatMap(w -> Arrays.stream(w.split(""))) .collect(groupingBy(identity(), counting())) .entrySet() .stream() .sorted(Map.Entry.comparingByValue(reverseOrder()).thenComparing(Map.Entry.comparingByKey())) .collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> {throw new IllegalStateException();}, LinkedHashMap::new)); 

产生:

 {a=5, n=3, e=2, p=2, g=1, l=1, o=1, r=1, s=1}