Home > Software design >  How to get top 3 records in ArrayList<Employee> with java OPP?
How to get top 3 records in ArrayList<Employee> with java OPP?

Time:05-20


I have 2 files a.txt and b.txt.
a.txt has 3 columns: id, name and month

e1,David,12
e2,Jane,24
e4,Peter,15
e3,John,25
...

b.txt has 2 columns: id and baseSalary
e1,1200
e2,1800
e4,2400
...

I will read a.txt to an ArrayList.

public ArrayList<Employee> loadEmployee(String file) {
        ArrayList<Employee> Emp = new ArrayList<Employee>();
        ArrayList<String> employees = loadFile(file);

        for (String emp : employees) {
            String[] data = emp.split(",");
            Emp.add(new Employee(data[0], data[1], Integer.parseInt(data[2])));
        }

        return Emp;
}

public class Employee{
    private String id;
    private String name;
    private int month;
    
    public Employee(String id, String name, int month){
        this.id=id;
        this.name=name;
        this.month=month;
    }
        
    public double getSalary(int baseSalary){
        return this.month*baseSalary;
    }
    
    public String toString(){
        return this.id "_" this.name "_" this.month;
    }
}

Now I want to get top 3 employee has highest salary.But you cannot create new class. I don't know how to do. I'm new in java OPP.
I think I will read b.txt to a hashmap, but hashmap cannot sort. So I cannot get top 3.
Anyone can help me?
Sorry if my English is not good.

CodePudding user response:

But you cannot create new class.

You don't need to declare a new class for that.

I'll give you a couple of hints on how to deal with your assignment.

Firstly, you need to define a Comparator, for that you can implement its method compare(), or if are familiar with Java 8 features you may use static method Comparator.comparing().

The next step is sorting.

You can sort the whole list of Employee, but it's not very efficient since you need only 3 objects. The second hint: use PriorityQueue.

If you choose to use a PriorityQueue the algorithm would be the following:

  • Iterate over the list of Employee;
  • At each step of iteration check whether the queue size is less then 3, and if it is the case add the current employee into the queue. If queue size is equal to 3, then using method element() (or peek()) get the lowers value in the queue and compare it with the current employee using comparator. If current employee has a greater salary it should be added into the queue, and the previous lowest value has to be removed (using either remove() or poll()).

CodePudding user response:

Your loadEmployee method is a good start, but as you said you have to read the second file to get the base salary for each employee and compute their overall salary (I guess it's a total income).

You could define a second method, setEmployeeBaseSalary, which accepts the second file's name and the List of employees. Then, you basically read the second file in the same way you've done with the first one. For each id read, you perform a search through your List, gather the employee by its id and set then set its base salary.

After updating your List of employees, you could use the collection stream to sort your list by salary, gather the first three results and then collect them into a new List.

public static ArrayList<Employee> loadEmployee(String file) {
    //your exact same implementation
}

public static ArrayList<Employee> setEmployeeBaseSalary(String file, List<Employee> list) {
    ArrayList<Employee> Emp = new ArrayList<>();
    try (FileReader fr = new FileReader(file);
         BufferedReader br = new BufferedReader(fr)) {

        Employee emp;
        String line = br.readLine();

        while (line != null) {
            String[] data = line.split(",");

            //Looking for an employee by the id read
            emp = list.stream().filter(employee -> employee.getId().equals(data[0])).findFirst().orElse(null);
  
            //If an employee with that id has been found then it's base salary is set
            if (emp != null) {
                emp.setBaseSalary(Double.parseDouble(data[1]));
            }

            line = br.readLine();
        }
    } catch (FileNotFoundException e) {
        throw new RuntimeException(e);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    return Emp;
}

Test main

public static void main(String[] args) {
    //Reading the list of employees
    ArrayList<Employee> listEmployee = loadEmployee("a.txt");

    //Setting the base salary for each employee
    setEmployeeBaseSalary("b.txt", listEmployee);

    //Retrieving the top three salary employees
    List<Employee> listTopThreeEmployee = listEmployee.stream()
            .sorted(Comparator.comparingDouble(Employee::getSalary).reversed()) //sorting each employee by their salary in reversed order (from the highest to the lowest)
            .limit(3) //Limiting the stream to the top three results
            .collect(Collectors.toList()); //Collecting the top three employees in a new list

    System.out.println(listTopThreeEmployee);
}

In addition, you should add within your Employee class setter and getter methods to set up and retrieve the Employee's fields.

class Employee {
    private String id;
    private String name;
    private int month;

    private double baseSalary;

    public Employee(String id, String name, int month) {
        this.id = id;
        this.name = name;
        this.month = month;
        this.baseSalary = 0;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getMonth() {
        return month;
    }

    public void setMonth(int month) {
        this.month = month;
    }

    public double getBaseSalary() {
        return baseSalary;
    }

    public void setBaseSalary(double baseSalary) {
        this.baseSalary = baseSalary;
    }

    public double getSalary() {
        return this.month * this.baseSalary;
    }

    public String toString() {
        return "("   this.id   "-"   this.name   "-"   this.month   "-"   baseSalary   "-"   getSalary()   ")";
    }
}

On a side note: variables representing currency should be declared as BigDecimal rather than double, as it is important to have an exact representation of the value rather than an approximation. In fact, the double precision tries to represent the value as closely as possible, but it's not said that it corresponds to the actual value assigned.

  •  Tags:  
  • java
  • Related