Java For循环替换:For循环到过滤器
我正在为计算机科学III课程(Java编程)做作业,其中我们必须基于哈夫曼编码对文件进行编码Java For循环替换:For循环到过滤器,java,for-loop,filter,stream,file-processing,Java,For Loop,Filter,Stream,File Processing,我正在为计算机科学III课程(Java编程)做作业,其中我们必须基于哈夫曼编码对文件进行编码 import java.util.Scanner; import java.util.ArrayList; import java.io.*; import java.util.Collections; import java.util.StringTokenizer; public class Client { public static void main(String[] args) thro
import java.util.Scanner;
import java.util.ArrayList;
import java.io.*;
import java.util.Collections;
import java.util.StringTokenizer;
public class Client {
public static void main(String[] args) throws IOException {
// TODO code application logic here
Scanner in = new Scanner(System.in);
System.out.println("Enter a filename to read from.");
String filename = in.nextLine();
File file = new File(filename);
Scanner inputFile = new Scanner(file);
String line, word;
StringTokenizer token;
ArrayList<Character> chars = new ArrayList<>();
while(inputFile.hasNext()){
line = inputFile.nextLine();
ArrayList<Character> lineChar = new ArrayList<>();
for (int i=0; i<line.length(); i++){
if (line.charAt(i)!=' '){
lineChar.add(line.charAt(i));
}
}
chars.addAll(lineChar);
}
ArrayList<Character> prob = new ArrayList<Character>();
for (int i=0; i<chars.size(); i++){
if (!prob.contains(chars.get(i))){
prob.add(chars.get(i));
}
}
for (int i=0; i<prob.size(); i++){
System.out.print("Frequency of " + prob.get(i));
System.out.println(": " + ((double)Collections.frequency(chars, prob.get(i)))/chars.size());
}
我真的,真的,真的对这很感兴趣,但我发现很难追踪所有的东西。显然,它的运行方式与for循环相同,测试后我发现它确实有效,但我想了解原因和方法。有人能给我一些见解吗?您的IDE用新的Java 8特性(流和lambda表达式)替换了一些代码。你应该读一下 流允许您对管道中的集合执行操作,其中只有最终(终端)操作对元素进行实际迭代(只针对所需的元素) Lambda表达式允许您在将实现函数接口(=具有单个方法的接口)的匿名类实例传递给方法时编写更少的代码 下面尝试解释新代码的作用:
chars.stream() // creates a Stream<Character> from your chars List
.filter((char1) -> (!prob.contains(char1))) // keeps only Characters not contained
// in prob List
.forEach((char1) -> {prob.add(char1);}); // iterates over all the elements of
// the Stream (i.e. those that weren't
// filtered out) and adds them to prob
prob.stream() // creates a Stream<Character> of the prob List
.map((prob1) -> {
System.out.print("Frequency of " + prob1);
return prob1;
}) // prints "Frequency of " + character for the current Character in the Stream
.forEach((prob1) -> { // prints the frequency of each character in the Stream
System.out.println(": " + ((double) Collections.frequency(chars, prob1)) / chars.size());
});
实际上,这不需要流,因为集合在Java 8中也有一个forEach
方法:
prob.forEach((prob1) -> { // prints the frequency of each character in the Stream
System.out.print("Frequency of " + prob1);
System.out.println(": " + ((double) Collections.frequency(chars, prob1)) / chars.size());
});
在我看来,NetBeans重构了您的代码,以使用Java8的lambda或使用流接口中的map-reduce的函数式编程操作 有关map()/reduce()/stream接口的更多信息,请参阅
请先阅读IDE提供的建议,然后再应用它们:)首先,您应该阅读有关该软件包的内容,以便对API的设计以及目的有一个第一印象 以下是您的第一个循环以word形式执行的操作:
- 迭代从0到chars.size()-1的值,并将相应元素从
添加到chars
,但前提是该元素尚未存在prob
实现ArrayList
,从而实现方法Collection
- 此流(管道中集合中的所有元素)正在被筛选(通过您以前的if语句)
- 在剩余元素的流上,执行最后的操作
prop.add
//...
.forEach(prop::add);
为了更好地理解或调试,您可能会发现有趣的方法。Netbeans尽其所能重构代码以使用java 8流,但实际上可以做得更好。例如,prob似乎应该包含一个不同的字符列表。在java 8中,您可以这样做:
List<Character> prob = chars.stream()
.distinct()
.collect(Collectors.toList());
我们使用字符映射进行计数,对其条目进行流式处理,按照值的相反顺序对它们进行排序,然后将每个条目打印出来。这些是使用lambda表达式的Java 8流。真是太棒了!我该如何根据频率对其进行排序?
chars.stream()
.filter(char1 -> !prob.contains(char1))
.forEach(char1 -> {
prob.add(char1);
});
//...
.forEach(prop::add);
List<Character> prob = chars.stream()
.distinct()
.collect(Collectors.toList());
Map<Character, Long> freq = chars.stream()
.collect(
Collectors.groupingBy(
x->x,
Collectors.counting()
)
);
Map<Character, Long> freq = chars.stream()
.collect(groupingBy(x->x, counting());
Stream<Character> charStream = Files.lines(Paths.get(filename))
.flatMap(line -> line.chars().mapToObj(i->(char) i));
public static void main(String[] args) throws IOException {
Scanner in = new Scanner(System.in);
System.out.println("Enter a filename to read from.");
String filename = in.nextLine();
Map<Character, Long> freq = Files.lines(Paths.get(filename))
.flatMap(line -> line.chars().mapToObj(i -> (char) i))
.collect(groupingBy(x -> x, counting()));
long total = freq.values().stream().mapToLong(x->x).sum();
freq.forEach((chr, count) ->
System.out.format("Frequency of %s: %s%n", chr, ((double) count) / total)
);
}
freq.entrySet().stream()
.sorted(comparing(e->e.getValue(), reverseOrder()))
.forEach(e -> System.out.format("Frequency of %s: %s%n", e.getKey(), (double) e.getValue() / total));