kirill leonov
kirill leonov

Reputation: 81

How to simplify chain of predicates in Kotlin

I have a chain of predicate clauses, something like this

student?.firstName?.equals("John") ?: false &&
student?.lastName?.equals("Smith") ?: false &&
student?.age?.equals(20) ?: false &&
student?.homeAddress?.equals("45 Boot Terrace") ?: false &&
student?.cellPhone?.startsWith("123456") ?: false

I have found that instead of && it's possible to switch to Boolean predicate and(), but overall it doesn't make code more concise.

Is there is a way in Kotlin to simplify such expression?

Upvotes: 4

Views: 2696

Answers (3)

remykarem
remykarem

Reputation: 2469

Not exactly what OP wants, but it seems like the issue here is comparing between two objects of type Student rather than chaining predicates.

Not sure what the use case is but here's a more object-oriented solution, where we park the predicates under Student::isSimilarToJohn (because I'm assuming this John Smith is pretty special):

data class Student(
    val firstName: String?,
    val lastName: String?,
    val age: Int?,
    val homeAddress: String?,
    val cellPhone: String?,
) {
    fun isSimilarToJohn(): Boolean {
        return firstName == "John" &&
            lastName == "Smith" &&
            age == 20 &&
            homeAddress == "45 Boot Terrace" &&
            cellPhone.orEmpty().startsWith("123456")
    }
}

Example:

val students = listOf(
    Student("John", "Smith", 20, "45 Boot Terrace", "1234568"),
    Student("John", "Smith", 20, "45 Boot Terrace", "1234567"),
    Student("Mary", "Smith", 20, "45 Boot Terrace", "1234567"),
    Student("John", "Doe",   20, "45 Boot Terrace", "1234567"),
)
students.map { it.isSimilarToJohn() }
// [true, true, false, false]

Upvotes: 0

kirill leonov
kirill leonov

Reputation: 81

Thanks everyone who participated! Here is a final version of the code with notes:

student?.run {
  firstName == "John" &&
  lastName == "Smith" &&
  age == 20 &&
  homeAddress == "45 Boot Terrace" &&
  cellPhone.orEmpty().startsWith("123456")
} ?: false
  1. Scope function run {} is called on an object student
  2. equals is replaced by == to compare boolean as well as null values
  3. return type of scope function is nullable, so elvis operator is used ?: false. Another option is to use == true, but it's your personal preference

Upvotes: 4

Stanley Wintergreen
Stanley Wintergreen

Reputation: 385

For example

val result = listOf(
    student.firstName == "John",
    student.lastName == "Smith",
    student.age == 20,
    student.cellPhone.orEmpty().startsWith("123456")
).all { it }

or

fun isAllTrue(first: Boolean, vararg other: Boolean): Boolean {
    return first && other.all { it }
}

val result = isAllTrue(
    student.firstName == "John",
    student.lastName == "Smith",
    student.age == 20,
    student.cellPhone.orEmpty().startsWith("123456")
)

or

fun Iterable<Boolean>.isAllTrue(): Boolean {
    return all { it }
}

val result = listOf(
    student.firstName == "John",
    student.lastName == "Smith",
    student.age == 20,
    student.cellPhone.orEmpty().startsWith("123456")
).isAllTrue()

Upvotes: 0

Related Questions