首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用Java 8 Stream API进行计数和排序

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

Stack Overflow用户
提问于 2015-10-23 02:21:47
回答 2查看 2.1K关注 0票数 4

我想知道这是怎么通过计数然后ASC来排序的。

代码语言:javascript
运行
复制
Stream<String> fruits = Stream.of("apple", "orange", "ananas");

Map<String, Long> letters =
   fruits.map(w -> w.split(""))
              .flatMap(Arrays::stream)
              .collect(groupingBy(identity(), counting()));

输出:

代码语言:javascript
运行
复制
{p=2, a=5, r=1, s=1, e=2, g=1, l=1, n=3, o=1}`

所需输出:

代码语言:javascript
运行
复制
{a=5, n=3, e=2, p=2, g=1, l=1, r=1, s=1, o=1}
EN

回答 2

Stack Overflow用户

发布于 2015-10-23 02:58:02

这是不可避免的在两个映射步骤中完成,因为您首先需要计数,然后才能根据计数进行排序:

代码语言:javascript
运行
复制
Map<String, Long> 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生成生成对象:

代码语言:javascript
运行
复制
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<String, Long> 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);
票数 5
EN

Stack Overflow用户

发布于 2015-10-23 02:57:27

您不能按值对映射进行排序。我认为最好的方法是将排序后的条目存储到一个LinkedHashMap中,这样当您迭代其他条目时,就会得到预期的结果(因为您将按所需的排序顺序添加映射)。

为此,您需要第一个group by操作来了解如何构建“Letter -> occurrences”映射(您也可以考虑使用Map<Character, Long>)。

然后,您必须再次迭代条目集,并对流进行排序,以便条目首先按其值排序,然后按键的自然顺序排序。因此,比较器将如下所示:

代码语言:javascript
运行
复制
//need to provide explicit type parameters due to limited type inference at the moment
Comparator<Map.Entry<String, Long>> cmp = 
    Map.Entry.<String, Long>comparingByValue(reverseOrder()).thenComparing(Map.Entry.comparingByKey());

把所有的部分放在一起,它就会产生:

代码语言:javascript
运行
复制
Map<String, Long> letters =
    fruits.flatMap(w -> Arrays.stream(w.split("")))
          .collect(groupingBy(identity(), counting()))
          .entrySet()
          .stream()
          .sorted(Map.Entry.<String, Long>comparingByValue(reverseOrder()).thenComparing(Map.Entry.comparingByKey()))
          .collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> {throw new IllegalStateException();}, LinkedHashMap::new));

这会产生:

代码语言:javascript
运行
复制
{a=5, n=3, e=2, p=2, g=1, l=1, o=1, r=1, s=1}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33288018

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档