I have a list, each element with the following fields:
active: true/false, optional_id: Int?, name: String
I am filtering for fields that have active true, to get the highest optional_id.
testList.filter { it.active == true }
.maxByOrNull { it.optional_id }
?. optional_id ?: 0
The idea is, if there are objects in the list, with the field active true, to get the highest optional_id amongst those.
Else, if they are all false (no active field), then return 0.
But since optional_id is of type Int?, maxByOrNull does not accept it without asserting !!. Is there any other way to handle null assertions for this scenario ?
I can't change the type of optional_id.
You can use maxOfWithOrNull with a nullsFirst comparator.
val highestOptionalId = testList.filter { it.active == true }
.maxOfWithOrNull(nullsFirst(naturalOrder())) { it.optionalId }
?: 0
"Of" suggests that it returns the selector's value, rather than the object in the list. "With" suggests that it uses a Comparator.
Is this what you are looking for?
testList.filter { it.active && it.optional_id != null }
.maxByOrNull { it.optional_id!! } ?.optional_id
?: 0
Following filter(...) you can safely assume (looks like you have no concurrency concerns) that optional_id is not null in maxByOrNull.
Related
This question already has answers here:
Regular Expression In Android for Password Field
(13 answers)
Closed 1 year ago.
I'm new in Kotlin and trying to find the most elegant solution of password validation with conditions:
Password must be at least 8 characters.
It must have at least 1 lowercase and at least 1 uppercase letter.
It must have one special character like ! or + or - or similar
It must have at least 1 digit
"Elegant" is subjective!
Here's a functional approach to it:
// you can define each rule as a separate checking function,
// adding more doesn't change the complexity
fun String.isLongEnough() = length >= 8
fun String.hasEnoughDigits() = count(Char::isDigit) > 0
fun String.isMixedCase() = any(Char::isLowerCase) && any(Char::isUpperCase)
fun String.hasSpecialChar() = any { it in "!,+^" }
// you can decide which requirements need to be included (or make separate lists
// of different priority requirements, and check that enough of each have been met)
val requirements = listOf(String::isLongEnough, String::hasEnoughDigits)
val String.meetsRequirements get() = requirements.all { check -> check(this) }
fun main() {
val password = "hiThere2!+"
println(password.meetsRequirements)
}
I think the benefit is it's easy to add new rules and they can be very simple and readable, and you can handle the validation logic in a separate step (e.g. if you're implementing a "password strength" metric, where meeting some requirements counts more than others).
I've used some fancier language features in there, but it's to keep it concise really. The String.whatever() extension functions just mean you don't need to reference the string parameter in the function (it's this), and the function references (String::hasEnoughDigits) let you do that requirements.all call instead of going if (isLongEnough(password) && hasEnoughDigits(password) && ...) and so on. You could do it that way if you wanted!
Lots of options and ways to approach it. Regexes can definitely be elegant, but they can also be hard to work with
You can do like this ...
internal fun isValidPassword(password: String): Boolean {
if (password.length < 8) return false
if (password.filter { it.isDigit() }.firstOrNull() == null) return false
if (password.filter { it.isLetter() }.filter { it.isUpperCase() }.firstOrNull() == null) return false
if (password.filter { it.isLetter() }.filter { it.isLowerCase() }.firstOrNull() == null) return false
if (password.filter { !it.isLetterOrDigit() }.firstOrNull() == null) return false
return true
}
I need to condense the following lines in kotlin to a more elegant way. I'm not able to figure out how to check the optional and the values at the same time. Basically I need to verify the list 'a' exists, has one or more items and that they are not 0.
val a = Utils.getItems() // returns an Optional<ImmutableList<ItemChange>>
if(!a.orElse(ImmutableList.of()).size > 0) {
val nonZero = a.get().filter { it.item != BigDecimal.ZERO }
return nonZero.size > 0
}
Assuming you also want to return false if non-existent or size 0, this is how I'd do it.
The any function returns true if any value matches, so it already takes care of the case of an empty list. And it breaks immediately if any match is found, whereas filter will exhaustively check the whole List and allocate a new List to hold the results.
Guava Optional can simply be converted to nullable with orNull() because Kotlin already has null-safety built in.
val items = Utils.getItems().orNull()
return items != null && items.any { it.item != BigDecimal.ZERO }
folks!
We know, IF statement only works with true condition. The operator ? checks and guarantees firstName property is not null. So, if firstName isn't null and isEmpty() is also true, why "==true" is needed?
Shortly, why simple condition "firstName?.isEmpty()" is invalid?
class Person (firstName: String?) {
init {
if (firstName?.isEmpty() == true) {
println("firstName is null")
}else{
println("The name is $firstName")
}
}
}
The operator ? checks and guarantees firstName property is not null.
No, safe call operator doesn't guarantees this. It guarantees that you won't get NullPointerException if firstName is null, instead you will get null as a result of
firstName?.isEmpty() expression.
So, the type of this expression is Boolean?, and if condition must be Boolean.
I believe, you'd better use firstName.isNullOrEmpty() here.
It is because firstName?.isEmpty() can be true, false, or null.
if (null) does not make sense
UNLESS you are using a language that implicitly converts null to true or false.
Kotlin does not implicitly convert it.
IsEmpty will be called in this case only if firstName is not null
Do note that the code does not work as intended (i.e. prints null if it is null or empty)
https://pl.kotl.in/H7rBIT8H6
fun main() {
var firstName:String? = null
if(firstName?.isEmpty() ==true){
//print("firstName is null")
print("test1: TRUE. ") //<<-- THIS WILL NOT BE PRINTED
}else {
print ("test1: FALSE. ") // <<-- THIS IS RETURNED INSTEAD
}
firstName = ""
if(firstName?.isEmpty() ==true){
print("test2: TRUE. ") //<<--WORKS AS INTENDED
}else {
print ("test2: FALSE. ")
}
firstName = "Hello"
if(firstName?.isEmpty() ==true){
print("test1: TRUE. ")
}else {
print ("test1: FALSE. ") //<<--WORKS AS INTENDED
}
}
The output is
test1: FALSE. test2: TRUE. test1: FALSE.
notice "test1" is FALSE?
what is happening is the code
"firstName?.isEmpty()" returns null if firstName is null.
and consequently, "null == true" will return false
So instead, what you should do is either call
firstName.isNullOrEmpty()
or
firstName==null || firstName?.isEmpty()==true
The issue here is that your list is nullable. In Kotlin you should always avoid having nullable values. I would suggest refactoring.
Anyway, the answer is:
Comparison needed because the list is nullable and you need a fallback because if the list is null, isEmpty() will not be called so you will not get a boolean value or condition which is needed for if.
use isNullOrEmpty() instead
So i want to compare three members of an array with as little code as possible. Heres what i did:
for(i in 0..2) {
if(board[i][0] == board[i][1] == board[i][2]) {
return true
} else if(board[0][i] == board[1][i] == board[2][i]) {
return true
}
}
(All of the values ar Char's FYI) But it didnt work. I get this error message "Operator '==' cant be applied to 'Boolean' and 'Char'". I also tried using .equals, but that just didnt work. Any ideas on what to do?
You can write a small function to keep it more readable and tidy, especially if You need to do that comparison often:
fun allEqual(vararg items: Any) : Boolean {
for(i in 1..(items.size-1)){
if(items[0] != items[i]) return false
}
return true
}
And invoke simply by comma separating values:
allEqual(board[i][0], board[i][1], board[i][2])
I don't know Kotlin specifically, but most* languages don't allow you to compare 3 values at the same time. What your error message is communicating is that your code ends up comparing
"Is board[i][0] equal to board[i][1]?" which is true/false (Boolean)
to
board[i][2], which is a Char.
*I don't know of any, but maybe there's one out there that does.
You have included this condition:
if(board[i][0] == board[i][1] == board[i][2])
Firstly, this one is compared: board[i][1] == board[i][2]
After comparing, it returns true. After that if logic converts to:
if(board[i][0] == true)
Now, board[i][0] is a char and you are trying to compare it to a boolean which is not possible. That's why you are getting this error.
You have to change the logic to:
if((board[i][0] == board[i][1]) && (board[i][1] == board[i][2]))
So, your code will be:
for(i in 0..2) {
if((board[i][0] == board[i][1]) && (board[i][1] == board[i][2])) {
return true
} else if((board[0][i] == board[1][i]) && (board[1][i] == board[2][i])) {
return true
}
}
Another approach:
for (i in 0..2) {
if (board[i].toSet().size == 1)
return true
else if (board.map { it[i] }.toSet().size == 1)
return true
}
As the others said, your first comparison returns Boolean, and the second compares Boolean to Char.
You can use an extension function, and transitivity to simplify things:
fun Any.equalsAll(vararg others: Any):Boolean
{
others.forEach {
if(it!=this)
return false
}
return true
}
and call:
if (board[0][i].equalsAll(board[1][i], board[2][i]))
For simple check like
if (variable != null) {
doSomething(variable)
}
We could change to
variable?.let { doSometing(it) }
However for a case with else
if (variable != null) {
doSomething(variable)
} else {
doOtherThing()
}
Is there a way of doing so in a single function? Is there something like either?
You can use the elvis-operator ?: like so:
variable?.let { doSomething(it) } ?: doOtherThing()
However personally I think that this gets quite unreadable very quickly. There is nothing wrong with an if-expression.
Another approach which might ring well with functional style is the use of when, which is very close to pattern matching:
when(variable) {
null -> doOtherThingSomething()
else -> doSomething(variable)
}
I would argue, however, that you should be careful with abandoning the classic if statement, if what you're after is its natural purpose - conditional execution. If you're calculating a value in two different ways and then using it in the same way, this approach makes sense. But if your code paths diverge at this point and don't meet again, then if provides a clearer intent.
You can map null-able value if not null by using ternary operator to check not null condition with If...Else Statements.
Here, I had wrote some code snippet to check value null or not ,
Case 1: value initialized
fun main(args: Array<String>) {
val value:Int ?= 10
val mapped = value?.let { "Value is == $value" } ?: "Value not initialized..."
println(mapped)
}
You gotta result: Value is == 10
Case 2: value set remains null
fun main(args: Array<String>) {
val value:Int ?= null
val mapped = value?.let { "Value is == $value" } ?: "Value not initialized..."
println(mapped)
}
You gotta result: Value not initialized...