寒假作业(2/2)— 疫情统计

寒假作业(2/2)

这个作业属于哪个课程 2020春W班
这个作业要求在哪里 作业要求
这个作业的目标 构建之法、PSP表格、Github使用、疫情统计程序...
作业正文 ....
其他参考文献 ...

一、Github仓库地址

作者仓库地址
主仓库地址

二、PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 15 20
Estimate 估计这个任务需要多少时间 15 20
Development 开发 990 905
Analysis 需求分析 (包括学习新技术) 180 200
Design Spec 生成设计文档 60 30
Design Review 设计复审 30 30
Coding Standard 代码规范 (为目前的开发制定合适的规范) 60 50
Design 具体设计 120 130
Coding 具体编码 360 325
Code Review 代码复审 60 55
Test 测试(自我测试,修改代码,提交修改) 120 85
Reporting 报告 90 95
Test Report 测试报告 30 40
Size Measurement 计算工作量 20 25
Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 40 30
合计 1095 1020

三、解题思路描述

  • 首先是命令行参数的识别。在CSDN上学习了相关知识:java学习之命令行参数通过命令行传递参数
  • 其次是日志的读取。学会了读取指定文件夹内所有文件的知识:JAVA基础知识之File类
  • 再次是分析日志内容的编码。因为有些偷懒,所以没有去学习JAVA的正则表达式,写了一大堆代码。后来想想,这样反而浪费了时间,也没有学到这个知识,真的是,。
  • 最后是txt文档的生成。就是先得到结果,在输出到文件。

四、设计实现过程

因为做作业的时候,时间也比较紧张了,所以并没有花心思设计几个类、几个函数。结果呢,就把代码塞到了main函数里,幸好代码量不是太多。下面就是一些示意图:
数据结构
算法流程

五、代码说明

1. 处理命令行参数

//得到存放各类型命令行参数的ArrayList具体值
for (int i=0;i<args.length;i++)
{
	if (args[i].equals("-log")) {
		logList=args[++i];
		//System.out.println(logList);
		logList=logList.replace('/', '\\');
		//System.out.println(logList);
	}
	else if (args[i].equals("-out")) {
		outList=args[++i];
		outList=outList.replace('/', '\\');
	}
	else if (args[i].equals("-date")) {
		dateList=args[++i];
	}
	else if (args[i].equals("-type")) {
		for (int j=i+1;j<args.length;j++) {
			if (!args[j].equals("-out")&&!args[j].equals("-date")&&
				!args[j].equals("-log")&&!args[j].equals("-province"))
			{
				typeList.add(args[j]);
			}
			else 
			{
				i=j-1;
				break;
			}
		}
	}
	else if (args[i].equals("-province")) 
	...
	}
}//获取ArrayList循环结束

2. 处理日志文件

//处理日志中的数据
for(String s:arr)
{
	if (s.compareTo(dateList+".log")>0)
	{
		continue;
	}
	File afile = new File(logList+s);
    Scanner sc = new Scanner(afile);
    while (sc.hasNext()) 
    {
        String first=sc.next();
        if (first.equals("//")) 
        {
        	sc.nextLine();
        } 
        else 
        {
        	int index=0;
        	for (int i=0;i<32;i++)
        	{
        		if (first.equals(province[i]))
        		{
        			index=i;
        			break;
        		}
        	}
        	number[0][4]=1;
        	number[index][4]=1;
        	String second=sc.next();
            if (second.equals("新增")) 
            {
            	String third=sc.next();
            	String four=sc.next();
            	four=four.replace("人", "");
            	int member=Integer.parseInt(four);	                	
            	if (third.equals("感染患者"))
            	{
            		number[0][0]+=member;
            		number[index][0]+=member;
            	}
            	else
            	{
            		number[0][1]+=member;
            		number[index][1]+=member;
            	}
            }
            else if (second.equals("感染患者"))
            ...       	
    }
    sc.close();
}

3. 将从日志文件得到的数据转化为所需数据

//得到输出结果
ArrayList<String> result=new ArrayList<String>();
if (provinceInt.size()==0)
{
	if (typeInt.size()==0)
	{
		for (int i=0;i<32;i++)
    	{
			if (number[i][4]==0)
			{
				continue;
			}
			String mid=province[i]+" 感染患者"+""+number[i][0]+""+"人"+" 疑似患者"+""+number[i][1]+""+"人"
			+" 治愈"+""+number[i][2]+""+"人"+" 死亡"+""+number[i][3]+""+"人\n";
			result.add(mid);
    	}
	}
	else
	{
		for (int i=0;i<32;i++)
    	{
			if (number[i][4]==0)
			{
				continue;
			}
			String mid=province[i];
			for (int j=0;j<typeInt.size();j++)
			{
				if (typeInt.get(j)==0)
				{
					mid=mid+" 感染患者"+""+number[i][0]+""+"人";
				}
				else if (typeInt.get(j)==1)
				...
			}
			mid+="\n";
			result.add(mid);
    	}
	}
}
else
{
	for (int i=0;i<32;i++)
	{
		number[i][4]=0;
	}
	for (int i=0;i<provinceInt.size();i++)
	{
		number[provinceInt.get(i)][4]=1;
	}
	if(typeInt.size()==0)
	{
		for (int i=0;i<32;i++)
    	{
			if (number[i][4]==0)
			{
				continue;
			}
			String mid=province[i]+" 感染患者"+""+number[i][0]+""+"人"+" 疑似患者"+""+number[i][1]+""+"人"
			+" 治愈"+""+number[i][2]+""+"人"+" 死亡"+""+number[i][3]+""+"人\n";
			result.add(mid);
    	}
	}
	else
	...
}

六、单元测试截图和描述

由于我写代码之前没有仔细看单元测试的内容,所以把所有的代码都写到了main函数里,这就很难测试每一个代码片段了。所以写完以后,我只能修改了一下自己的代码,这样起码main函数可以得到测试结果,。
测试代码

import static org.junit.Assert.*;

import org.junit.Test;

public class InfectStatisticTest 
{
	@Test
	public void testMain() 
	{
		String[] test1=("list -log D:/log/ -out D:/ListOut1.txt -date 2020-01-22").split(" ");
		//for(int i=0;i<test1.length;i++)
		//System.out.println(test1[i]);		
		InfectStatistic.main(test1);		
		assertEquals("全国 感染患者15人 疑似患者22人 治愈2人 死亡1人\n", InfectStatistic.result.get(0));
		assertEquals("福建 感染患者5人 疑似患者7人 治愈0人 死亡0人\n", InfectStatistic.result.get(1));
		assertEquals("湖北 感染患者10人 疑似患者15人 治愈2人 死亡1人\n", InfectStatistic.result.get(2));
		
		
//		String[] test2=("list -log D:/log/ -out D:/ListOut2.txt -date 2020-01-22 -province 福建 河北").split(" ");	
//		InfectStatistic.main(test2);		
//		assertEquals("福建 感染患者5人 疑似患者7人 治愈0人 死亡0人\n", InfectStatistic.result.get(0));
//		assertEquals("河北 感染患者0人 疑似患者0人 治愈0人 死亡0人\n", InfectStatistic.result.get(1));
//		
//		String[] test3=("list -log D:/log/ -out D:/ListOut7.txt -date 2020-01-23 -type cure dead ip -province 全国 浙江 福建").split(" ");		
//		InfectStatistic.main(test3);		
//		assertEquals("全国 治愈4人 死亡3人 感染患者42人\n", InfectStatistic.result.get(0));
//		assertEquals("福建 治愈1人 死亡0人 感染患者9人\n", InfectStatistic.result.get(1));
//		assertEquals("浙江 治愈0人 死亡0人 感染患者0人\n", InfectStatistic.result.get(2));		
	}
}

三个测试结果截图
test1
test2
test3
看起来一样,。

七、单元测试覆盖率优化和性能测试,性能优化截图和描述

单元测试覆盖率
怎么说呢,因为我是直接测试main函数,所以命令行要么带province要么不带province,要么带type要么不带type,就不能一次测试把所有情况都覆盖,难搞。
此处输入图片的描述

八、代码规范的链接

https://github.com/massizhi/InfectStatistic-main/blob/master/221701141/codestyle.md

九、心路历程与收获

艰辛!做这个项目,发现自己不会的太多了。原来以为在实验室做了几个项目,自己的工程能力应该不错了,结果用到的都是自己的知识盲区。比如实验室用SVN,这里用Git,虽然都是代码管理工具,学起来也十分吃力。自己比较懒,做作业的时候距离截止时间也不多了,所以做的比较匆忙。当然了,不会的东西多,学到的就多,争取对这个项目经历能做一个详细的总结吧。收获也是挺多的,比如软件工程的初步了解、Github的使用、对自己第一次作业定的目标的资料收集、Java命令行参数的获取、Java输入输出等、构建之法、单元测试等。

十、第一次作业中技术路线图相关的5个仓库

  • 谷歌全新开源人工智能系统TensorFlow官方文档: TensorFlow官方文档
    机器学习作为人工智能的一种类型,可以让软件根据大量的数据来对未来的情况进行阐述或预判。「TensorFlow」是 Google 多年以来内部的机器学习系统。

  • 人工智能实战微信小程序demo小程序demo
    里面为很多微信小程序的demo,AI学到一定程度就可以参考demo编写自己的程序了。

  • AI-Practice-Tensorflow-NotesTensorflow笔记
    里面为人工智能实践:Tensorflow笔记 。

  • 机器学习相关教程https://github.com/MorvanZhou/tutorials

    Python 基础
    基础
    多线程 threading
    多进程 multiprocessing
    简单窗口 tkinter
    机器学习
    有趣的机器学习
    强化学习 (Reinforcement Learning)
    进化算法 (Evolutionary Algorithm) 如遗传算法等
    Tensorflow (神经网络)
    PyTorch (神经网络)
    Theano (神经网络)
    Keras (快速神经网络)
    Scikit-Learn (机器学习)
    机器学习实战
    数据处理
    Numpy & Pandas (处理数据)
    Matplotlib (绘图)
    爬虫
    其他
    Git (版本管理)
    Linux 简易教学

  • 吴恩达老师的机器学习课程个人笔记: https://github.com/fengdu78/Coursera-ML-AndrewNg-Notes
    本课程提供了一个广泛的介绍机器学习、数据挖掘、统计模式识别的课程。主题包括:
    1、监督学习(参数/非参数算法,支持向量机,核函数,神经网络)。
    2、无监督学习(聚类,降维,推荐系统,深入学习推荐)。
    3、在机器学习的最佳实践(偏差/方差理论;在机器学习和人工智能创新过程)。

附:总结及改进

1. Github使用

参考资料Git基础命令Github Desktop入门Commit message 和 Change log 编写指南Git教程

常用命令
git init : 在需要发送的项目的文件夹的根目录下右键【git bash here】

git add : 将本地文件增加到暂存区
git add . : 此命令表示当前目录的所有文件

git commit : 将暂存区的内容提交到本地仓库(本地分支,默认master分支),会跳出文本编辑器,可以写多行注释。
git commit -m "注释内容"

git remote add origin git@...(唯一标识符SSH):本地项目-远程项目关联

git push : 将本地仓库内容推送到远程仓库(远程分支)
git push -u origin master : 第一次发布项目
git push origin master : 非第一次发布项目

git clone git@...(唯一标识符SSH):从远程下载项目到本地
git pull :将远程仓库(远程分支)内容拉取到本地仓库(本地分支),即更新项目
git pull origin master

中间疑问

  1. 本地项目与远程项目关联是什么意思?
    答:我的理解是两个项目有联系才能互相更新。比如:clone到本地的项目不需要建立关联,因为本身就具有联系。而本地新建的项目则需要与远程项目相关联。
  2. 暂存区指的是什么?
    答:工作区(Working Directory)是在电脑里能看到的目录,工作区有一个隐藏目录.git,这个是Git的版本库(Repository)。Git的版本库里存放了称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。可以简单理解为,我们将需要提交的文件修改放到暂存区(add),然后,提交暂存区的所有修改到分支(commit)。
  3. 分支的含义?master分支是默认创建的分支吗?origin代表什么?
    答:做作业时没有用到分支,只是对master有些疑惑。现在明白了,master分支是默认创建的分支,分支就像自己的另外一个版本,可以在上面修改、测试。当然,具体命令还是有点复杂的,。 master是一个本地分支,origin是默认的远程版本库名称。
  4. fork与pr的含义?
    答:Fork:克隆别人的代码库到自己的github项目中,可以作为子模块的形式使用,或二次开发 。Pull requests (PR): Fork之后,如果希望将自己的修改贡献到原始代码中,可以使用pull requests推送请求到原来仓库中,然后原始代码的作者,根据你提交的内容,考虑是否真的放入源码中。

关于commit
Commit message 包括三个部分:Header(必需),Body(可选)和 Footer(可选)。
Header 部分只有一行,包括三个字段:type(必需)、scope(可选)和subject(必需)。
type 用于说明 commit 的类别,只允许使用下面7个标识。

    feat:新功能(feature)
    fix:修补bug
    docs:文档(documentation)
    style: 格式(不影响代码运行的变动)
    refactor:重构(即不是新增功能,也不是修改bug的代码变动)
    test:增加测试
    chore:构建过程或辅助工具的变动

scope用于说明 commit 影响的范围,subject是 commit 目的的简短描述(动词开头)。

2. 正则表达式

参考资料:菜鸟教程这个更实用些
正则表达式定义了字符串的模样(结构...),对于匹配字符串很好用,加上捕获组,满足了我预想的功能。为什么要把正则表达式单独拉出来,就是想提醒一下我自己。平时懒惰,晚做作业,不想学新东西,到最后还不是得补上!!!

3. 代码重构

插旗-ing

posted @ 2020-02-18 20:45  massizhi  阅读(306)  评论(3编辑  收藏  举报