【问题标题】:Parse two files and generate employee data [closed]解析两个文件并生成员工数据 [关闭]
【发布时间】:2018-03-19 06:58:45
【问题描述】:

假设我们有两个使用逗号分隔值的日志文件。 file1.txt 代表employee idemployee namefile2.txt 代表他关联的employee idprojectsfile1 具有唯一条目。 file2 会有多对多的关系。如果新员工没有分配任何项目,则在file2.txt 中没有任何条目。

File1.txt:(EmpId, EmpName)
1,abc
2,ac
3,bc
4,acc
5,abb
6,bbc
7,aac
8,aba
9,aaa

File2.txt: (EmpId, ProjectId)
1,102
2,102
1,103
3,101
5,102
1,103
2,105
2,200
9,102

Find the each employee has been assigned to number of projects. For New employees if they dont have any projects print 0;
Output:
1=3
2=3
3=1
4=0
5=1
6=0
7=0
8=0
9=1

我使用 BufferedReader 从file1 中读取一行并将其与file2 中的每一行进行比较。下面是我的代码,

public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        BufferedReader file1 = new BufferedReader(new FileReader("file1.txt"));
        BufferedReader file2 = new BufferedReader(new FileReader("file2.txt"));
        BufferedReader file3 = new BufferedReader(new FileReader("file2.txt"));
        HashMap<String,Integer> empProjCount = new HashMap<String, Integer>();
        int lines =0;
        while (file2.readLine() != null) 
            lines++;
        String line1 = file1.readLine();
        String[] line_1 = line1.split(",");
        String line2 = file3.readLine();
        String[] line_2 = line2.split(",");
        while(line1 != null && line2 != null)
        {
            int count = 0;
            for(int i=1;i<=lines+1 && line2 != null;i++)
            {
            if(line_1[0].equals(line_2[0]))
            {
                count++;
            }
            line2 = file3.readLine();
            if(line2 != null){
                line_2 = line2.split(",");
            }
            }
            file3 = new BufferedReader(new FileReader("file2.txt"));
            empProjCount.put(line_1[0], count);
            line1 = file1.readLine();
            if(line1 != null) line_1 = line1.split(",");
            line2 = file3.readLine();
            if(line2 != null) line_2 = line2.split(",");
        }
        System.out.println(empProjCount); 

我的问题是,

  1. 有什么方法可以优化它小于 O(n^2),而不使用任何额外的空间?

  2. 我使用 3 BufferedReader 读取file2.txt,因为一旦我们读取一行,它就会移动到下一行。有没有其他选项可以标记当前行?

  3. 如果我们将其视为一个表,那么查询上述场景的最佳方法是什么?

【问题讨论】:

  • SO 不是要求进行代码审查的最佳场所
  • 如果你不使用任何SQL,为什么要标记它sql?在 SQL 中,它是一个简单的 select emp.EmpId, count(*) from emp left join proj on e.EmpId = Proj.EmpId group by emp.EmpId
  • 性能:n是file1中的记录数和file2中的m,可以在O(n*m)O(1)内存中完成,或者在O(n+m)和@987654344中完成@内存。
  • 我投票结束这个问题,因为它属于Code Review
  • @Stultuske@JimGarrison 我没有发布我的代码以供审查。我只是发布它来展示我的方法,并为此做了一些工作。我的实际问题是如何以不同的方式处理它。如果它仍然不属于这里,请告诉我。

标签: java sql file bufferedreader filereader


【解决方案1】:

对于 1:是的。

对于 2:是的:

我会在两次迭代中完成:

  1. 迭代 ID (file1) 并初始化映射 (empId, projectCounter)

  2. 迭代项目 (file2) 并为每一行更新 (projectCounter++) 地图中的相应条目。

这样,您的执行时间几乎是线性的(对于 file1 和 file2 的大小)。

【讨论】:

    【解决方案2】:

    file 1 收集所有员工ID 的Map,并将其初始化为包含0 用于项目计数。

        // Build my map of all employees.
        Map<Integer, Integer> employeeProjectCount = Arrays.stream(file1)
                // Get empId - Split on comma, take the first field and convert to integer.
                .map(s -> Integer.valueOf(s.split(",")[0]))
                // Build a Map for the results.
                .collect(Collectors.toMap(
                        // Key is emp ID.
                        empId -> empId,
                        // Value starts at zero.
                        empId -> ZERO
                ));
    

    浏览file 2 数项目。

        // Walk the projects list.
        Arrays.stream(file2)
                // Get empId - Split on comma, take the first field and convert to integer (again).
                .map(s -> Integer.valueOf(s.split(",")[0]))
                // Count the projects.
                .forEach(empId -> employeeProjectCount.put(empId, employeeProjectCount.get(empId)+1));
    

    打印出来:

        // Print it.
        System.out.println(employeeProjectCount);
    

    给予

    {1=3, 2=3, 3=1, 4=0, 5=1, 6=0, 7=0, 8=0, 9=1}

    顺便说一句:我以String[]s 的身份处理这些文件。

    String[] file1 = {
            "1,abc",
            "2,ac",
            "3,bc",
            "4,acc",
            "5,abb",
            "6,bbc",
            "7,aac",
            "8,aba",
            "9,aaa",};
    String[] file2 = {
            "1,102",
            "2,102",
            "1,103",
            "3,101",
            "5,102",
            "1,103",
            "2,105",
            "2,200",
            "9,102",
    };
    

    【讨论】:

      【解决方案3】:

      使用Files.lines 和正则表达式:

      Pattern employeePattern = Pattern.compile("(?<id>\\d+),(?<name>\\s+)");
      Set<String> employees = Files.lines(Paths.get("file1.txt"));
          .map(employeePattern::matcher).filter(Matcher::matches)
          .map(m -> m.group("id")).collect(Collectors.toSet());
      
      Pattern projectPattern = Pattern.compile("(?<emp>\\d+),(?<proj>\\d+)");
      Map<String,Long> projects = Files.lines(Paths.get("file2.txt"))
          .map(projectPattern::matcher).filter(Matcher::matches)
          .collect(Collectors.groupingBy(m -> m.group("emp"), Collectors.counting());
      

      并打印结果:

      employees.stream()
          .map(emp -> emp + "=" + projects.getOrDefault(emp, 0L))
          .forEach(System.out::println);
      

      【讨论】:

        猜你喜欢
        • 2013-01-13
        • 2011-12-23
        • 1970-01-01
        • 2011-03-19
        • 1970-01-01
        • 2011-09-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多