前言
最近看到一篇内容记一篇机试题:原文地址
当时评论了一句,你这么写我一定给零分。由于最近比较忙,一直没有给作者一个答复,今天稍微有点空,算是给稍微普及一下面向对象的思想吧。想想当初自己写码代码也是如此码过来的,不经唏嘘。
原文简要介绍
题目
/**
* 1 输出每个人的名字及其平均成绩
* 2 以平均成绩的升序排序
* 3 有良好的命名和注释
* 4 要体现面向对象以及代码的可复用性
*
* 输出结果
* 王五 40
* 张三 70
* 李四 75
*/
public class jh {
public static void main(String[] args) {
List<String> list = Arrays.asList(new String[]{"1,张三,90","2,李四,70","3,王五,40","4,张三,50","5,李四,80"});
}
}
原作者解决方案
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
/**
* 1 输出每个人的名字及其平均成绩
* 2 以平均成绩的升序排序
* 3 有良好的命名和注释
* 4 要体现面向对象以及代码的可复用性
*
* 输出结果
* 王五 40
* 张三 70
* 李四 75
*
* 我解题的思路:
* 首先把字符串拆分,将名字、分数各自放到一个list集合
* 然后用for循环比较,名字相同的,其分数相加 --> 存储的顺序一样即两个list的index对应关系一样
* --| 后面可能有重复的名字的处理:将循环到的数据用一个for循环与前面的相比较,如果有相同的,continue到最外层的for循环,否则执行下面操作
* --| 如果没有与前面相同的,内嵌一个for循环,与后面的名字相比较,如果相同,将对应的分数相加
* --| 将名字与平均分数封装到Student对象中,将Student对象放到一个list集合
* --| 将Student的list集合使用冒泡排序算法排序
* --| 遍历Student的list集合,按顺序输出结果
*/
public class jh {
public static void main(String[] args) {
//原题
List<String> list = Arrays.asList(new String[]{"1,张三,90", "2,李四,70", "3,王五,40", "4,张三,50", "5,李四,80"});
// List<String> list = new ArrayList<>();
// Scanner scanner = new Scanner(System.in);
// System.out.println("请输入学生的信息(序号,名字,分数)标点符号用中文,*号退出:");
//
// while (scanner.hasNext()){
// String student = scanner.next();
// if (student.equals("*")) {
// break;
// }
// list.add(student);
// System.out.println("请输入学生的信息(序号,名字,分数)标点符号用中文,*号退出:");
// }
//用于存放名字
List<String> nameList = new ArrayList<String>();
//用于存放成绩
List<Integer> gradeList = new ArrayList<>();
//用于存放Student对象
List<Student> studentList = new ArrayList<>();
//遍历题目的list
for (String student : list) {
//按“,”分割字符串,返回一个数组
String[] msg = student.split(",");
//将名字存放到list中
nameList.add(msg[1]);
//将分数存放到list中
gradeList.add(Integer.parseInt(msg[2]));
}
outer:
for (int i = 0; i < nameList.size(); i++) {
//用于记录总分数
int grade = gradeList.get(i);
//用于记录共加了多少个人的分数
int count = 1;
//如果当前的名字与前面的相同,跳出循环
for (int y = 0; y < i; y++) {
if (nameList.get(i).equals(nameList.get(y))) {
continue outer;
}
}
//若没有跳出循环则执行下面的for循环,将后面的与当前名字相同的分数相加,记录到grade总分数中
for (int j = i + 1; j < nameList.size(); j++) {
if (nameList.get(i).equals(nameList.get(j))) {
grade += gradeList.get(j);
count++;
}
}
//创建一个Student对象,存放名字和平均分
Student student = new Student();
student.setName(nameList.get(i));
student.setAvg(grade / count);
//将Student对象放到list集合中
studentList.add(student);
}
// System.out.println(studentList);
//冒泡排序,升序
for (int i = 0; i < studentList.size(); i++) {
for (int j = i + 1; j < studentList.size(); j++) {
if (studentList.get(i).getAvg() > studentList.get(j).getAvg()) {
Student s = studentList.get(i);
studentList.set(i, studentList.get(j));
studentList.set(j, s);
}
}
}
// System.out.println(studentList);
//遍历输出结果
for (Student student : studentList) {
System.out.println(student.getName() + " " + student.getAvg());
}
}
}
简单点评
丝毫没有面向对象的概念,JAVA的优势全丢了,没有一点可取之处。机试的目的并不是实现功能,而是看你的代码结构和编码能力还有那么一点点习惯。
改造后的代码
学生类
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Student {
private String name;
}
成绩记录单类
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ScopeRecode {
/**
* 学生
*/
private Student student;
/**
* 分数
*/
private Integer scope;
/**
* 将字符串数据转换为成绩记录
* @param data "1,张三,90" 参考格式
* @return 成绩记录
*/
public static ScopeRecode ofStringData(String data){
if(!data.contains(","))return null;
String[] datas = data.split(",");
Student student = Student.builder().name(datas[1]).build();
return ScopeRecode.builder().student(student).scope(Integer.valueOf(datas[2])).build();
}
}
成绩管理类
public class ScopeManager {
private Map<Student, List<ScopeRecode>> studentScopeRecord;
ScopeManager(){
studentScopeRecord = new HashMap<>();
}
public void record(ScopeRecode scopeRecode){
Student student = scopeRecode.getStudent();
studentScopeRecord.computeIfAbsent(student, k -> new ArrayList<>());
List<ScopeRecode> scopeRecodes = studentScopeRecord.get(student);
scopeRecodes.add(scopeRecode);
}
public void recordBach(List<ScopeRecode> scopeRecodeList){
scopeRecodeList.forEach(this::record);
}
/**
* 获取按平均成绩排序后的结果
* @return
*/
public List<Map.Entry<Student, Integer>> getAverageScoreStatisticsOrderByScore(){
Map<Student, Integer> averageScoreStatistics = getAverageScoreStatistics();
//按照value排序
List<Map.Entry<Student, Integer>> entryArrayList = new ArrayList<>(averageScoreStatistics.entrySet());
entryArrayList.sort(Comparator.comparingInt(Map.Entry::getValue));
return entryArrayList;
}
/**
* 获取统计的平均成绩
* @return
*/
private Map<Student,Integer> getAverageScoreStatistics(){
Set<Student> students = studentScopeRecord.keySet();
Map<Student,Integer> dataMap = new HashMap<>();
students.forEach(temp -> {
dataMap.put(temp, getAverageScope(temp));
});
return dataMap;
}
/**
* 获取某个学生的平均成绩
* @param student
* @return
*/
private Integer getAverageScope(Student student){
List<ScopeRecode> scopeRecodes = studentScopeRecord.get(student);
if(scopeRecodes == null){
return null;
}else{
Integer sumScope = 0;
int num = scopeRecodes.size();
for(ScopeRecode scopeRecode : scopeRecodes){
sumScope += scopeRecode.getScope();
}
return sumScope / num;
}
}
}
调用类(此类名为和原文保持一致,未修正类名首字符大写的问题)
public class jh {
public static void main(String[] args) {
List<String> list = Arrays.asList(new String[]{"1,张三,90","2,李四,70","3,王五,40","4,张三,50","5,李四,80"});
List<ScopeRecode> scopeRecodeList = new ArrayList<>();
list.forEach(temp -> scopeRecodeList.add(ScopeRecode.ofStringData(temp)));
ScopeManager scopeManager = new ScopeManager();
scopeManager.recordBach(scopeRecodeList);
List<Map.Entry<Student, Integer>> averageScoreStatisticsOrderByScore = scopeManager.getAverageScoreStatisticsOrderByScore();
for(Map.Entry<Student,Integer> entry : averageScoreStatisticsOrderByScore){
System.out.println(entry.getKey().getName() +" " + entry.getValue());
}
}
}