【华为机试】简单错误记录 JAVA全过程详解

该博客介绍了如何开发一个简单的错误记录功能模块,能够记录并处理错误的文件名、行号和出现次数。模块要求能存储最多8条错误记录,对相同的错误进行合并计数,并按错误出现次数和首次出现的顺序排序。文章详细阐述了错误类的设计,包括文件名处理、错误计数、数据结构选择(ArrayList)以及排序和输出的方法。提供的完整代码实现了这一功能,适用于处理带有路径的文件名输入,并能根据需求输出错误信息。
摘要由CSDN通过智能技术生成

一、题目描述

【注意】该题是华为2016年秋招机试题目,与牛客网中的HJ19略有不同,请看清题目要求,两题代码不通用。
开发一个简单错误记录功能小模块,能够记录出错的代码所在的1文件名称name、2行号row、3错误出现次数count。
要求:
(1)记录最多8条错误记录,对相同的错误记录(即文件名称name和行号row均相同)只记录一条,错误计数增加;(文件所在的目录不同,文件名和行号相同也要合并);
(2)超过16个字符的文件名称,只记录文件的最后有效16个字符(如果文件名不同,而只是文件名的后16个字符和行号相同,也不要合并);
(3)输入的文件可能带路径,记录文件名称不能带路径
数据范围:输入错误记录数量[1,1000],每条记录的长度[1,50] 。

1. 输入

若干行windows格式的文件路径字符串。每行包括带路径文件名称、行号,以空格隔开。

如:E:\V1R2\product\fpgadrive.c 1325

2. 输出

格式:文件名+代码行数+数目,以一个空格隔开。
按照数目从多到少排序,数目相同的情况下,按照输入时第一次出现的顺序排序。如果超过8条记录,则只输出前8条记录。

如: fpgadrive.c 1325 1

3. 样例

由于题目描述中只有上面的那个简单样例,因此笔者又自己创建了样例仅供参考。

输入:
A:\V1R2\product\mygoodjob.c 1325
A:\V1R2\product\mygoodjob.c 1325
B:\V1R2\product\abcdefghijklmnopqrst.exe 12
C:\V1R2\product\abcdefghijklmnopqrst.exe 12
A:\V1R2\product\moneymoney.c 1326
loveyouHW.html 521
loveyouHW.html 521
loveyouHW.html 521
loveyouHW.html 521
输出:
loveyouHW.html 521 4
mygoodjob.c 1325 2
ijklmnopqrst.exe 12 2
moneymoney.c 1326 1

二、思路分析

题目描述很乱,我们来梳理一下思路。

1. 关于错误

容易看出,每个错误有4个属性,分别是String name文件名、int row错误行数、int order首次出现的顺序、int count出现的次数。

其中,name文件名 + row错误行数,可以唯一地标识一个错误,相当于错误的ID。而order首次出现的顺序 + count出现次数用于对错误进行排序:当两个错误的count不一样时,count大的在前;而当count一样时,order小的(先出现)的在前。

那么,当初始化一个错误的时候,就应该应该赋予它name、row、order的值,并把count置为1;当再次遇到这个错误的时候,就把count++;为了使用name+row唯一标识一个错误,要重写hashcode和equals方法。由此我们就有了对错误类MyError的初步定义:

class MyError
    {
        private String name;
        private int row;
        private int order;
        private int count;
        
        MyError(String name, int row, int order){	// 初始化方法
        this.name = name;
        this.row = row;
        this.order = order;
        count = 1;
    }
    void addCount() { count++; }			// 再次遇到时count++
    int getCount()  { return count;}
    int getOrder()  { return order;}
    @Override
    public int hashCode() {
    // name是String类型自带hashCode方法,再加入row即可。掺杂name和row的方法比较灵活,只要能体现出用name+row标识错误即可
        return row + name.hashCode();
    }
    @Override
    public boolean equals(Object o) {
    // hashCode一致的情况下,进一步比较name和row的内容,确保完全一样
        if ( ((MyError) o).name.equals(name) && ((MyError) o).row==row )
            return true;
        return false;
    }
}

2. 数据结构和输入

完成MyError的初步定义后,可以考虑数据结构和输入的问题了。选择的数据结构有3点要求:1错误记录的数量是未知的,因此要可变长;2最好能快速读取修改;3能允许我们按照MyError的count和order排序,因此选择了可变数组ArrayList。

		ArrayList<MyError> errList = new ArrayList<>();

接下来就可以输入了,由于要记录错误出现的顺序,所以要引入变量order,初值为1,每读完一个错误就++。由此得到输入的大框架。

        int order = 1;
        while (sc.hasNext())
        {
        	//*************
        	// 进行各种操作
        	//*************
            order++;
        }

现在填充中间的操作内容。先读文件名称name,由于题干中说 “ 输入的文件可能带路径 ” ,所以要加入判断。如果能在字符串中找到“\”则说明带路径,要从最后一个“\”的位置截取到字符串末尾,从而把干干净净的文件名拿出来;如果不带“\”则说明直接给出了文件名,可以不作处理使用。

		String tempName = sc.next();        // 错误文件名
		if (tempName.indexOf("\\")!=-1)     // 有\就截取,没有就原封不动
			tempName = tempName.substring(tempName.lastIndexOf('\\')+1,tempName.length());

然后读取错误行数row,直接调用一次sc.nextInt()即可,接着就可以实例化一个MyError对象了。

		MyError tempErr = new MyError( tempName, sc.nextInt(), order );

最后检查新创建的对象tempErr是否是errList中已经保存过的错误,如果是则将其出现次数count++;否则作为新错误加入errList。刚刚定义MyError类时已经完成了addCount()方法,并重写了hashCode()和equals(),所以直接用就行了。

		if ( errList.indexOf(tempErr) != -1 )                       // 有则次数+1,无则新增
			errList.get( errList.indexOf(tempErr) ).addCount();
		else
			errList.add( tempErr );

3. 排序

经过前两步的工作,错误记录的读取和errList的创建已经完成,现在只需要对errList中的对象按照count和order排序即可。这里使用Collections.sort()对errList这个ArrayList类型排序,重写其排序规则compare()。

		Collections.sort(errList, new Comparator<MyError>() {
            @Override
            public int compare(MyError o1, MyError o2) {           // 重写排序方式,计数相等就按照顺序;否则按照计数
                return o2.getCount()==o1.getCount() ? o1.getOrder()-o2.getOrder() : o2.getCount()-o1.getCount() ;
            }
        });

4. 输出

该题对输出有2个数量上的要求:1是若超出8条记录,则只输出前8条;2是若文件名长度超过16,则只输出后16字符。

做到这里我们补充下之前定义过的MyError类,新增方法String getOutput()直接返回正确的输出String。当文件名超过16时进行截取再输出。

    	String getOutput()
    	{
        	if (name.length()<=16)      // 判断如果长度超过16,就要截取
            	return name+" "+String.valueOf(row)+" "+String.valueOf(count);
        	else
        	{
            	String tempStr = name.substring(name.length()-16,name.length());
            	return tempStr+" "+String.valueOf(row)+" "+String.valueOf(count);
        	}
    	}

最后使用for循环输出结果,直接借助Math.min函数即可。如果超过了8条,min()函数结果为8;如果少于8条,min()函数结果为errList长度。避免了更多判断。

        for ( int i=0; i<Math.min(8,errList.size()); i++ )      // 要么全部输出,要么输出8个,取决于Math.min的结果
            System.out.println(errList.get(i).getOutput());

三、完整代码

笔者的完整源代码如下,可以直接提交通过该题。使用自定义类+ArrayList并不是最快最省空间的解法,但是思路清晰易懂、容易实现,仅供大家参考。如各位大神有更好的想法欢迎留言讨论,期待与您共同进步!

import java.util.*;

public class Main {
    public static void main(String[] agrs)
    {
        Scanner sc = new Scanner(System.in);

        ArrayList<MyError> errList = new ArrayList<>();
        int order = 1;
        while (sc.hasNext())
        {
            String tempName = sc.next();        // 错误文件名
            if (tempName.indexOf("\\")!=-1)     // 有\就截取,没有就原封不动
                tempName = tempName.substring(tempName.lastIndexOf('\\')+1,tempName.length());
            MyError tempErr = new MyError( tempName, sc.nextInt(), order++ );   // 设置错误文件名、错误行数、出现的顺序
            if ( errList.indexOf(tempErr) != -1 )                       // 有则次数+1,无则新增
                errList.get( errList.indexOf(tempErr) ).addCount();
            else
                errList.add( tempErr );
        }

        Collections.sort(errList, new Comparator<MyError>() {
            @Override
            public int compare(MyError o1, MyError o2) {           // 重写排序方式,计数相等就按照顺序;否则按照计数
                return o2.getCount()==o1.getCount() ? o1.getOrder()-o2.getOrder() : o2.getCount()-o1.getCount() ;
            }
        });

        for ( int i=0; i<Math.min(8,errList.size()); i++ )      // 要么全部输出,要么输出8个,取决于Math.min的结果
            System.out.println(errList.get(i).getOutput());
    }
}
class MyError
{
    private String name;
    private int row;
    private int order;
    private int count;
    MyError(String name, int row, int order){
        this.name = name;
        this.row = row;
        this.order = order;
        count = 1;
    }
    String getOutput()
    {
        if (name.length()<=16)      // 判断如果长度超过16,就要截取
            return name+" "+String.valueOf(row)+" "+String.valueOf(count);
        else
        {
            String tempStr = name.substring(name.length()-16,name.length());
            return tempStr+" "+String.valueOf(row)+" "+String.valueOf(count);
        }
    }
    void addCount() { count++; }
    int getCount()  { return count;}
    int getOrder()  { return order;}
    @Override
    public int hashCode() {
        return row+name.hashCode();
    }
    @Override
    public boolean equals(Object o) {
        if ( ((MyError) o).name.equals(name) && ((MyError) o).row==row )
            return true;
        return false;
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鲜衣怒马是山林

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值