Java vs TypeScript (through examples) — Part 2— Second highest salary (and with SQL too)
We will continue our series (Java vs TypeScript (through examples) — Part 1 — Two Sum | by Rahul Bansal | Jul, 2023 | Medium) and today, we will explore Java and TypeScript through another beautiful problem. The problem is stated as-
Given a list of employees with their department names, identify and output the employee with the 2nd highest salary in each department.
We will solve this problem in both Java and TypeScript. Importantly, we will also see how beautifully SQL solves it.
Let’s start with SQL. Assuming you have a table named “employees” with columns such as “employee_id,” “employee_name,” “department,” and “salary,” you can use the following:
SELECT department, employee_id, employee_name, salary
FROM (
SELECT
department,
employee_id,
employee_name,
salary,
RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS salary_rank
FROM employees
) ranked_employees
WHERE salary_rank = 2;
SQL natively supports partitions/grouping, ordering/sorting and ranking. This makes it easier to find the solution for any rank. The solution for highest salary per department is even simpler:
SELECT department, employee_id, employee_name, MAX(salary) AS max_salary
FROM employees
GROUP BY department;
Now, let’s try to achieve the same using TypeScript.
class Employee
{
constructor(
public employeeId: number,
public name: string,
public department: string,
public salary: number
) { }
}
// Assuming you have an array of Employee objects
const employees: Employee[] = [
new Employee(1, "John Doe", "Sales", 50000),
new Employee(2, "Jane Smith", "HR", 55000),
new Employee(3, "Bob Johnson", "Sales", 60000),
new Employee(4, "Alice Lee", "HR", 52000),
new Employee(5, "Mike Williams", "Finance", 48000),
new Employee(6, "Emily Brown", "Finance", 51000),
];
// Group employees by department using a Map
const employeesByDepartment = new Map<string, Employee[]>();
for (const employee of employees)
{
if (!employeesByDepartment.has(employee.department))
{
employeesByDepartment.set(employee.department, []);
}
employeesByDepartment.get(employee.department)?.push(employee);
}
// Find the second highest salary in each department
for (const [department, departmentEmployees] of employeesByDepartment)
{
if (departmentEmployees.length >= 2)
{
// Sort the employees within the department based on their salaries in descending order
departmentEmployees.sort((a, b) => b.salary - a.salary);
// Get the employee with the second highest salary
const secondHighestSalaryEmployee = departmentEmployees[1];
console.log(secondHighestSalaryEmployee);
console.log("-------------------------");
}
}
// Run with -> tsc .\second-highest-salary.ts --lib "es6,dom" --target "es2015"; node .\second-highest-salary.js
Pretty neat. We first created some employees and then put them into a map (which is equivalent to grouping them by department). Then we went through each department and used the sort function to order all the employees in a department. And then picked the index 1 which is the employee with the second highest salary.
The thing to notice here is that unlike SQL there is no native support for partitioning. We can’t say employeeArray.groupBy(“department”).orderBy(“salary”). In my view this should be supported by high level languages.
And now let’s try the same in Java. I will only highlight the key parts.
// Create a map to group employees by their departments
Map<String, List<Employee>> employeesByDepartment = new HashMap<>();
for (Employee employee : employees)
{
employeesByDepartment.computeIfAbsent(employee.getDepartment(), k -> new ArrayList<>()).add(employee);
}
// Find the second highest salary in each department
for (List<Employee> departmentEmployees : employeesByDepartment.values())
{
if (departmentEmployees.size() >= 2)
{
departmentEmployees.sort(Comparator.comparingDouble(Employee::getSalary).reversed());
// Get the employee with the second highest salary
Employee secondHighestSalaryEmployee = departmentEmployees.get(1);
// Print the result
System.out.println("Employee ID: " + secondHighestSalaryEmployee.getEmployeeId());
System.out.println("-------------------------");
}
}
Pretty much identical to the TypeScript solution (The two languages have come pretty close over a period of time). Again, no easy way to partition the data. We need to put the employees in a Map and then sort.
So that rounds up today’s discussion. We will continue to learn more in the upcoming articles. Till then, Happy Coding!