Java 使用流、无映射、无键值对计算和打印文本中的字符频率
我试图计算并打印文本中所有字符的频率。 我想使用Java 使用流、无映射、无键值对计算和打印文本中的字符频率,java,functional-programming,java-stream,Java,Functional Programming,Java Stream,我试图计算并打印文本中所有字符的频率。 我想使用数组或数组列表执行此操作,并且不使用带有键值对的映射 下面的代码给出了首选结果。 我想摆脱main的for循环 并使用方法countlets()完成所有工作 为了清楚起见,我希望以一种功能性的方式来实现这一点,而不使用任何for循环或if语句。 这能做到吗?如果是,怎么做 公开信柜4{ publicstaticvoidmain(字符串[]a){ 系统输出打印(“输入文本>”; int[]res=countLetters(); for(int i=
数组
或数组列表
执行此操作,并且不使用带有键值对的映射
下面的代码给出了首选结果。
我想摆脱main的for
循环
并使用方法countlets()
完成所有工作
为了清楚起见,我希望以一种功能性的方式来实现这一点,而不使用任何for循环或if语句。
这能做到吗?如果是,怎么做
公开信柜4{
publicstaticvoidmain(字符串[]a){
系统输出打印(“输入文本>”;
int[]res=countLetters();
for(int i=0;is.charAt(0))
.filter(字符::isleter)
收集(
()->新的ArrayList(Collections.nCopies(26,0)),
(李,埃尔)->{
整数oInt=li.get(el-'a');
li.set(el-'a',++oInt);
},
(结果1,结果2)->{
对于(int i=0;i
下面是示例代码,希望这是您要问的问题
import java.util.Arrays;
import java.util.Scanner;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class LetterCounter4 {
public static void main(String[] a) {
System.out.print("Input text > ");
countLetters();
}
private static void countLetters() {
try{
Arrays.stream(new Scanner(System.in).nextLine().toLowerCase()
.split(""))
.flatMap(line -> Stream.of(line.split("\\s+")))
.map(String::toLowerCase)
.collect(Collectors.toMap(word -> word, word -> 1, Integer::sum))
.entrySet()
.stream()
.sorted((a, b) -> a.getValue() == b.getValue() ? a.getKey().compareTo(b.getKey()) : b.getValue() - a.getValue())
.forEach(System.out::println);
}catch(Exception e){
e.printStackTrace();
}
}
}
最简单的方法是使用.groupingBy(c->c,Collectors.counting())
。代码会更简单,当有人输入À或[a-zA-Z]范围之外的其他字母时,代码不会爆炸。但这会创建一个地图,你说你不想要它
如果您特别希望坚持使用数组和列表,可以采用以下方法:
public static void main(String[] args) {
String input = new Scanner(System.in).nextLine();
int[] counts = countLetters(input);
IntStream.range(0, counts.length)
.filter(i -> counts[i] > 0)
.forEachOrdered(i -> System.out.printf("%c appears %s %s%n",
'a' + i,
counts[i],
counts[i] > 1 ? "times" : "time"
));
}
public static int[] countLetters(String s) {
return s.chars() // this is better than stream(split(""))
.filter(Character::isLetter) // WRONG to assume that all letters are [a-zA-Z]
.map(chr -> Character.toLowerCase(chr) - 'a')
.collect(
() -> new int[26],
(ary, i) -> ary[i]++,
(a,b) -> Arrays.setAll(a, i -> a[i] + b[i])
);
}
那么它只会打印列表的值,不是吗?但我无法将每个值都链接到相应的字符。除非我能知道我在每个步骤中打印的列表的索引。谢谢你的回复。这确实符合我的要求。但我不想使用for循环和if语句。只有函数式编程。如果您希望“空格”(“”)也被计算,则意味着从拆分函数中删除“\\s+”,这确实符合我的要求。collect的组合器可以由(a,b)->{for(inti=0;ia[i]+=b[i]作为setAll使用的函数接口中方法的主体。为什么只需将int i作为参数传递,而不必传递i、a、b?我希望函数接口要求3个参数。为了知道它必须使用的数组。@xtra抱歉,这是一个输入错误(尽管代码仍然有效)。它应该是i->a[i]+b[i]
i
被显式传递。a
和b
是从封闭范围中捕获的。当您说“错误地假设所有字母都是[a-zA-Z]”时,您不应该通过收集到长度为26
的固定大小数组中来犯同样的错误……或者,过滤[a-zA-Z]
或收集到支持其他字符的内容中。当支持所有unicode字母时,返回数组不是最佳选择…
public static void main(String[] args) {
String input = new Scanner(System.in).nextLine();
int[] counts = countLetters(input);
IntStream.range(0, counts.length)
.filter(i -> counts[i] > 0)
.forEachOrdered(i -> System.out.printf("%c appears %s %s%n",
'a' + i,
counts[i],
counts[i] > 1 ? "times" : "time"
));
}
public static int[] countLetters(String s) {
return s.chars() // this is better than stream(split(""))
.filter(Character::isLetter) // WRONG to assume that all letters are [a-zA-Z]
.map(chr -> Character.toLowerCase(chr) - 'a')
.collect(
() -> new int[26],
(ary, i) -> ary[i]++,
(a,b) -> Arrays.setAll(a, i -> a[i] + b[i])
);
}