为IntStream生成直方图Map会引发编译时错误

时间:2017-06-30 05:07:30

标签: java-8 grouping histogram java-stream aggregation

我对构建霍夫曼编码原型感兴趣。为此,我想首先生成构成输入Java String的字符的直方图。我在SO和其他地方看到了很多解决方案(例如:here依赖于collect()的{​​{1}}方法以及Stream和{{的静态导入1}}以非常具体和直观的方式。

然而,当使用一段与我上面链接的代码类似的代码时:

Function.identity()

我从Intellij收到一个编译时错误,它基本上告诉我Collectors.counting()没有符合private List<HuffmanTrieNode> getCharsAndFreqs(String s){ Map<Character, Long> freqs = s.chars().collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); return null; } 类型的参数,正如其签名所要求的那样:

Intellij's error message

不幸的是,我是Java 8 collect层次结构的新手,我不完全确定对我来说最好的行动方案应该是什么。事实上,走Supplier方式对于我正在尝试做的事情来说可能是太多了。请告知是否如此。

3 个答案:

答案 0 :(得分:4)

问题是s.chars()会返回IntStream - Stream的特定专长,而且它没有collect只需要一个参数;它的collect有3个参数。显然,您可以使用boxed,这会将IntStream转换为Stream<Integer>

Map<Integer, Long> map = yourString.codePoints()
          .boxed()
          .collect(Collectors.groupingBy(
                      Function.identity(), 
                      Collectors.counting()));

但现在问题是你已经计算了code-points而不是字符。如果你完全知道你的字符串是由BMP中的字符组成的,你可以安全地转换为char,如另一个答案中所示。如果你不是 - 事情就变得棘手了。

在这种情况下,你需要将单个unicode代码点作为一个字符 - 但可能不适合Java char - 它有2个字节;并且unicode字符最多可以包含4个字节。

在这种情况下,您的地图应该是Map<String, Long>而不是Map<Character, Long>

在java-9中引入了受支持的\X(和Scanner#findAll),这很容易做到:

 String sample = "A" + "\uD835\uDD0A" + "B" + "C";
         Map<String, Long> map = scan.findAll("\\X")
               .map(MatchResult::group)
               .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));


 System.out.println(map); // {A=1, B=1, C=1, =1}

在java-8中,这会更冗长:

    String sample = "AA" + "\uD835\uDD0A" + "B" + "C";
    Map<String, Long> map = new HashMap<>();

    Pattern p = Pattern.compile("\\P{M}\\p{M}*+");
    Matcher m = p.matcher(sample);

    while (m.find()) {
        map.merge(m.group(), 1L, Long::sum);
    }
    System.out.println(map); // {A=2, B=1, C=1, =1}

答案 1 :(得分:1)

String.chars()方法返回IntStream。您可能希望通过以下方式将其转换为Stream<Character>

s.chars().mapToObj(c -> (char)c)

答案 2 :(得分:0)

如前所述,您可以将流转换为基本类型到对象类型。

s.chars().boxed()
 .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));