【问题标题】:Counting and order with Java 8 Stream API使用 Java 8 Stream API 进行计数和排序
【发布时间】:2017-03-02 17:46:24
【问题描述】:

我想知道如何按 COUNT 然后按 ASC 排序。

Stream<String> fruits = Stream.of("apple", "orange", "ananas");

Map<String, Long> 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}

【问题讨论】:

    标签: java java-8 java-stream


    【解决方案1】:

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

    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生成生成:

    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);
    

    【讨论】:

      【解决方案2】:

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

      为此,您需要第一个按操作分组,以了解如何构建映射“字母 -> 出现次数”(您也可以考虑使用 Map&lt;Character, Long&gt;)。

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

      //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());
      

      将所有部分放在一起,结果是:

      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));
      

      产生:

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

      【讨论】:

        猜你喜欢
        • 2020-01-08
        • 2017-09-20
        • 1970-01-01
        • 2017-08-03
        • 1970-01-01
        • 2015-07-09
        • 1970-01-01
        • 2021-08-19
        • 2016-02-29
        相关资源
        最近更新 更多