4

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?

10
  • 1
    student?.run { firstName("John") && lastName("Smith") .. } kotlinlang.org/docs/reference/scope-functions.html#run Commented Nov 18, 2019 at 12:23
  • it will not compile because of nullable types. Expression && only works with safe non nullable types Commented Nov 18, 2019 at 12:29
  • 3
    student?.firstName?.equals("John") ?: false could be simplified to student?.firstName == "John", &c. (Because == handles nulls.) Commented Nov 18, 2019 at 12:35
  • instead of writing ?: false you can also just write == true... Commented Nov 18, 2019 at 15:05
  • 1
    If it is a data class and if you're comparing all properties, I would suggest to create student object with expected values, then just compare two data class objects like (yourStudent == expectedStudent). Commented Nov 18, 2019 at 15:44

3 Answers 3

4

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
Sign up to request clarification or add additional context in comments.

Comments

0

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() 

4 Comments

please revise your answer... you forgot to handle the nullable-type-issue...
Are you talking about the string "student.firstName ==" John "" where the firstName parameter is used as String??
From the question we see that student can be null already... so I rather meant student?.firstName, etc... Note also that with your current approach you lose the short-circuiting and unnecessarily create a list for each such condition...
I'd go for the first one but instead of listOf i'd go for setOf because it's faster than a list.
0

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] 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.