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 to3
, then using methodelement()
(orpeek()
) 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 eitherremove()
orpoll()
).
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.