Kotlin, How do I make a function for distinctBy method

Viewed 71

Suppose, I have this list which contains a list of employee info.

val distinctEmployee = employees.distinctBy { it.firstName }

I want to make a function and pass as a parameter for distinctBy method so I can apply any kind of distinct method to the list. I expect something like this.

val highSalaryEmployee = employees.filterBy(salaryFilter)

function salaryFilter(employee: Employee): Boolean {
  return employee.salary > 350000
}

I have done this with filterBy method before, but I dont know how to apply with distictBy method.

Edit: So this what I actually have tried and still got stuck.

val distinctEmployee = employees.distinctBy { firstNameDistinct(it) }

function firstNameDistinct(employee: Employee): Boolean {
  return employee. // what should be returned here?
}
1 Answers

I'm a little confused by what you are trying to do. If you could clarify, we can find an answer. But, I'll answer with some assumptions.

First, I think there is some confusion about what distinctBy does. From the Kotlin docs:

Returns a list containing only elements from the given array having distinct keys returned by the given selector function.

So, let's look at this code as an example:

fun test() {
    val employees = listOf(
        Employee("Bob", 75000),
        Employee("Jenna", 400000),
        Employee("Mark", 120000),
        Employee("Rebecca", 80000),
        Employee("Tanner", 30000),
        Employee("Bob", 45000)
    )
    
    val distinctEmployees = employees.distinctBy { it.name }
    distinctEmployees.forEach {
        println(it)
    }
}

class Employee(val name: String, val salary: Int) {
    override fun toString(): String = "Name: $name\tSalary: $salary"
}

This will be the output:

Name: Bob   Salary: 75000
Name: Jenna Salary: 400000
Name: Mark  Salary: 120000
Name: Rebecca   Salary: 80000
Name: Tanner    Salary: 30000

Notice it is a list, not just one employee - and Bob is only shown once even though there were originally two Bobs. Basically employees.distinctBy { it.name } is saying, "Give me a list of all the employees in this list, but only unique names, get rid of any employees with duplicate names."

Now comes the assumption - since you are using the name of employee, singular - I am assuming you don't want a list, but you want to grab an employee out of that list with a given name. To achieve this, you could do something like:

val employee = employees.firstOrNull { it.name == "Bob" }

But know that if there are multiple Bobs, you will only get one and it might be the "wrong" one depending on what you are doing with it. You could also do:

val filteredEmployees = employees.filter { it.name == "Bob" }

But that would get you a list:

Name: Bob   Salary: 75000
Name: Bob   Salary: 45000

So you could also do:

val employee = employees.firstOrNull { it.name == "Bob" && it.salary == 75000 }

But again, you could still run into a situation where two employees have the same name and same salary. I would suggest adding some kind of unique ID to the employee, and just doing firstOrNull on that:

fun test() {
    val employees = listOf(
        Employee("1234", "Bob", 75000),
        Employee("5678", "Jenna", 400000),
        Employee("9123", "Mark", 120000),
        Employee("4567", "Rebecca", 80000),
        Employee("8912", "Tanner", 30000),
        Employee("3456", "Bob", 45000)
    )
    
    // val employee = employees.filter { it.name == "Bob" }
    val employee = employees.firstOrNull { it.employeeID == "3456" }
    println(employee)
}

class Employee(val employeeID: String, val name: String, val salary: Int) {
    override fun toString(): String = "Name: $name\tSalary: $salary"
}

Output:


Name: Bob   Salary: 45000
Related