我对构建霍夫曼编码原型感兴趣。为此,我想首先生成构成输入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;
}
类型的参数,正如其签名所要求的那样:
不幸的是,我是Java 8 collect
层次结构的新手,我不完全确定对我来说最好的行动方案应该是什么。事实上,走Supplier
方式对于我正在尝试做的事情来说可能是太多了。请告知是否如此。
答案 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()));