如下就是Java的解题报告。
*背景*
现提供一个读文件的类,利用此类读取给定的文件。
实现对文件数据的处理,并输出。 要求:
- 显示文件所有信息,并 依次输出。
- 输出没有成绩的学生列表,设置此类学生的成绩为0分。
- 计算学生的平均成绩,并输出。
- 根据学生成绩排序,分别输出前三名的学生和排序的结果(由高到底)。
- 统计各个单姓姓氏的人数,依次输出。 例如: 张 3人 李 4人
每题目20分,共100分。
将运行结果展示给老师,并将工程文件打包上传
大概就是给我们了一个读取文件的类, 然后其他由我们自己实现。
这里是提供的文件: data (我把里面那个text.txt里面的人名换成了随机生成的字符串, 因为据说这是某个班真实的成绩>_<)
然后这里是我的原始代码: javaex
*万呆的源代码分析*
首先会有一个func1, 它其实就是老师提供给我的文件里面的, 我只不过抄过来了XD!
然后就是创建一个StudentCollection的实例。
StudentCollection sc = new StudentCollection(“d:\\text.txt”);
构造函数代码如下
public StudentCollection(String filename) { ReadFile rf = new ReadFile(filename); try { String[] lines=rf.openFile(); if(lines.length<=0) return; for(int i=1;i<lines.length;++i) { Student myStu = Student.parse(lines[i]); _totalScore+=myStu.getScore(); _lstStu.add(findScore(myStu.getScore()),myStu); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //如下是findScore方法, 不解释了, 这个方法不好, 参见下面的Collections.sort private int findScore(int score) { int ret=0; for(int i=0;i<_lstStu.size();++i) { if(_lstStu.get(i).getScore()>score) { ret=i+1; } } return ret; }
_lstStu.add(findScore(myStu.getScore()),myStu); 就是类似于插入排序(?)的一种东西, 可以每次把要加入的Student对象加入到它相应的位置, 这样添加完毕就自然排序完毕了~
_totalScore+=myStu.getScore(); 就是把所有的学生的分数给加起来, 以便之后获取平均分
顺便吐槽一下, 原来那个ReadFile这货需要读取两次文件! 第一次才获取行数!! 这是很浪费时间的>w<
其中解析Student的方法为:
public static Student parse(String x) { String name; int score=0; String[] val=x.split("\\s",2); name=val[0]; //输出没有成绩的学生列表,设置此类学生的成绩为0分。 if(val[1].length()>0) { score=Integer.parseInt(val[1]); } return new Student(name, score); }
考察.split方法, 我们需要给它提供两个参数, 一个是一种类似正则表达式的东西( \\s 中 \\ 是为了转义 \ , 其实就是 \s , 它会匹配所有的空白字符), 一个是最多分割的个数的值。
看val[1].length()>0, 它是判断val[1]是否有值, 也就是是否有分数, 没有的话默认就是零分。
另外, 正则表达式确实好用, 在这里也可以用一个正则表达式来实现处理每行数据的功能。
大概可以这样写 String rx=”^(?<name>.+?)(\\s+)(?<score>\\d{0,3})$”, 然后用一个正则表达式的包(java.util.regex)来实现, 这个有个好处就是可以一次把文件全部读入然后设置正则模式为多行, 然后一次处理就好了!
参考如下:
String src = "姓名 期末\r\ntwd2 100\r\nabc\t\r\n"; String rx = "^(?<name>.+?)(\\s+)(?<score>\\d{0,3})$"; Pattern p = Pattern.compile(rx, Pattern.MULTILINE); Matcher m = p.matcher(src); while(m.find()) { System.out.println(m.group("name") + "\t" + m.group("score")); }
有人总是说“嘿!这个问题我可以用正则表达式解决。”—然后他们就有两个问题了
于是我们得到了一个新鲜的学生的集合!
接下来就是输出啦。
其中我重写然后重载了一个toString方法, 其中一个重载是提供一个整数来限制最多输出多少个学生。
下面需要 统计各个单姓姓氏的人数,依次输出。 例如: 张 3人 李 4人
我用到了HashMap, 它以Character为key(键), Integer为value(值)。
HashMap<Character, Integer> map = new HashMap<;Character, Integer>(); for(Student stu:sc._lstStu) { if(!map.containsKey(stu.getFamilyName())) map.put(stu.getFamilyName(), 0); map.put(stu.getFamilyName(), map.get(stu.getFamilyName())+1); } Character[] key=new Character[map.keySet().size()]; map.keySet().toArray(key); for(int i=0;i<map.size();++i) { System.out.println(key[i] + " " + map.get(key[i]) + "人"); }
大概就是判断有没有这个键, 如果没有的话把它加进去, 否则值加1。
然后用了一种笨办法来获得所有的键, 然后分别输出这些键对应的值。
*后记*
后来发现有 Collections.sort 这个好东西。
于是修改如下
public StudentCollection(String filename) { ReadFile rf = new ReadFile(filename); try { String[] lines=rf.openFile(); if(lines.length<=0) return; for(int i=1;i<lines.length;++i) { Student myStu = Student.parse(lines[i]); _totalScore+=myStu.getScore(); _lstStu.add(/*findScore(myStu.getScore()),*/myStu); } Collections.sort(_lstStu); //分数递增排序 Collections.reverse(_lstStu); //反过来~ } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //Student类需要改为 public class Student implements Comparable 然后实现一个Comparable要求的方法compareTo。 @Override public int compareTo(Student o) { // TODO Auto-generated method stub return _score - o._score; }
显然这个sort方法是要比我自己写的排序是要好的。
PS.附赠随机字符串生成代码!
public static String genRandomString(int length) { String canuse="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; Random rand = new Random(); StringBuffer sb = new StringBuffer(); for(int i=0;i<length;++i) { sb.append(canuse.charAt(rand.nextInt(canuse.length()))); } return sb.toString(); }
确定这不是C#?
StringBuffer, 这不是C#, C#是StringBuilder
哦我错了StringBuilder在Java中也有, 他是非线程安全的。StringBuffer是线程安全的。