Operator '==' cant be applied to 'Boolean' and 'Char' - kotlin

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

Related

How to use if statement when function returns 2 arguments?

I recently created a function that checks if a pair exists in my swap smart contract.
The functoin looks like this:
function checkIfPairExists(address _token1, address _token2) internal returns(uint, bool) {
for (uint index = 0; index < tokenPairs.length; index++) {
if (tokenPairs[index].token1 == _token1 && tokenPairs[index].token2 == _token2) {
return (index, true);
}
else if (tokenPairs[index].token2 == _token1 && tokenPairs[index].token1 == _token2) {
return (index, true);
} else {
return (0, false);
}
}
}
This function works fine but then when I try to use the function in an if statement like this:
if (checkIfPairExists(_token1, _token2) == (uint256, true))
How do I write it so it is correct? I am trying to receive index of the pair for my array and bool to see if the pair exists. I then need to save that index to find which pair it should add to.
Hope it makes sense.
Let me know if I should rephrase the question so more people will understand it and it can help them.
Thanks
You need to assign the returned values to two separate variables. Then you can validate either of them.
(uint256 index, bool exists) = checkIfPairExists(_token1, _token2);
if (exists == true) {
// do something with `index`
}
As said in the above answer by #pert-hejda, you will need to assign the function return values then you can use those to check the condition. Why? Because multiple returns are represented as tuples and currently the feature you want is not supported in solidity. So, you will need to assign the return values and use those values in conditionals. Thank you.

Conditional max inside filter kotlin

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.

password validation with Kotlin [duplicate]

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
}

How to avoid !! in a function which returns a non-nullable

In the sample below, the function should return a non-null data.
Since the data could be changed in the process, it needs to be var, and can only be nullable to start with.
I can't use lateinit because the first call of if (d == null) will throw.
After the process it will be assigned a non-null data, but the return has to use the !! (double bang or non-null assertion operator).
What is the best approach to avoid the !!?
fun testGetLowest (dataArray: List<Data>) : Data {
var d: Data? = null
for (i in dataArray.indecs) {
if (d == null) {// first run
d = dataArray[i]
} else if {
d.level < dataArray[i].level
d = dataArray[i]
}
}
return d!!
}
If you don't like !! then supply a default value for it. You'll realize you can only supply the default value if the list is not empty, but, as you said, the list is already known to be non-empty. The good part of this story is that the type system doesn't track list size so when you say dataArray[0], it will take your word for it.
fun testGetLowest(dataArray: List<Data>) : Data {
var d: Data = dataArray[0]
for (i in 1 until dataArray.size) {
if (d.level < dataArray[i].level) {
d = dataArray[i]
}
}
return d
}
Normally, you can and should lean on the compiler to infer nullability. This is not always possible, and in the contrived example if the inner loop runs but once d is non-null. This is guaranteed to happen if dataArray has at least one member.
Using this knowledge you could refactor the code slightly using require to check the arguments (for at least one member of the array) and checkNotNull to assert the state of the dataArray as a post-condition.
fun testGetLowest (dataArray: List<Data>) : Data {
require(dataArray.size > 0, { "Expected dataArray to have size of at least 1: $dataArray")
var d: Data? = null
for (i in dataArray.indecs) {
if (d == null) {// first run
d = dataArray[i]
} else if {
d.level < dataArray[i].level
d = dataArray[i]
}
}
return checkNotNull(d, { "Expected d to be non-null through dataArray having at least one element and d being assigned in first iteration of loop" })
}
Remember you can return the result of a checkNotNull (and similar operators):
val checkedD = checkNotNull(d)
See Google Guava's Preconditions for something similar.
Even if you were to convert it to an Option, you would still have to deal with the case when dataArray is empty and so the value returned is undefined.
If you wanted to make this a complete function instead of throwing an exception, you can return an Option<Data> instead of a Data so that the case of an empty dataArray would return a None and leave it up to the caller to deal with how to handle the sad path.
How to do the same check, and cover the empty case
fun testGetLowest(dataArray: List<Data>)
= dataArray.minBy { it.level } ?: throw AssertionError("List was empty")
This uses the ?: operator to either get the minimum, or if the minimum is null (the list is empty) throws an error instead.
The accepted answer is completly fine but just to mentioned another way to solve your problem by changing one line in your code: return d ?: dataArray[0]

Compare String Kotlin

I'm studying kotlin, but I'm very disappointed, I can not compare two Strings.
What is the right way to compare.
btn_login.setOnClickListener {
val login = input_email.text.trim()
val pass = input_password.text.trim()
if( login.equals( pass ) ){
startActivity<MainActivity>()
}
if (login?.equals(other = pass)){
startActivity<MainActivity>()
}
if (login == pass){
startActivity<MainActivity>()
}
}
According to documentation for structual equality use ==. It is translated to a?.equals(b) ?: (b === null).
In you case convert login and pass from SpannableStringBuilder to String.
val login = input_email.text.trim().toString()
Here is the example for matching the two strings using kotlin.
If you are using == (double equals) for matching the string then it's compare the address & return maximum time wrong result as per java documentation so use equals for the same
If you want to use equal ignore case then pass the true in the equals method of String
if (s1.equals(s2,true))
other wise you can just use this without boolean like
if (s1.equals(s2,false)) or if (s1.equals(s2))
compleate code is below
fun main(args: Array<String>) {
val s1 = "abc"
val s2 = "Abc"
if (s1.equals(s2,true))
{
println("Equal")
}
else
{
println("Not Equal")
}
}
Covert both the SpannableStringBuilder to string with toString, this should work.
val login = input_email.text.trim().toString()
val pass = input_password.text.trim().toString()
if (login == pass){
startActivity<MainActivity>()
}
1. == :
if ( string1 == string2 ){...}
2. equals :
Indicates whether some other object is "equal to" this one.
Implementations must fulfil the following requirements:
Reflexive: for any non-null reference value x, x.equals(x) should
return true.
Symmetric: for any non-null reference values x and y, x.equals(y)
should return true if and only if y.equals(x) returns true.
Transitive: for any non-null reference values x, y, and z, if
x.equals(y) returns true and y.equals(z) returns true, then
x.equals(z) should return true
Consistent: for any non-null reference values x and y, multiple
invocations of x.equals(y) consistently return true or consistently
return false, provided no information used in equals comparisons on
the objects is modified.
/** * Returns `true` if this string is equal to [other], optionally ignoring character case. * * #param ignoreCase `true` to ignore character case when comparing strings. By default `false`. */
public fun String?.equals(other: String?, ignoreCase: Boolean = false): Boolean
3. compareTo :
public override fun compareTo(other: String): Int
Compares this object with the specified object for order. Returns zero
if this object is equal to the specified other object, a negative
number if it's less than other, or a positive number if it's greater
than other.
public fun String.compareTo(other: String, ignoreCase: Boolean = false): Int
Compares two strings lexicographically, optionally ignoring case
differences
i know this is way too late, but as a newbie learning Kotlin, i had the same doubts.
then i came across this wonderful article that articulates the various string comparison types in Kotlin and the differences between them all.
in short both == and .equals() can be used to compare the value of 2 strings in kotlin.
hopefully that helps
With case checking
String a=.....
String b=.....
if(a==b){
}
IgnoreCase
if(a.equals(b,false))
KOTLIN:
if (editText1.text.toString() == editText2.text.toString() ) {
println("Should work now! The same value")
}
Try the following solution, see if it helps:
val passStr: String = textView.text.toString()
if( loginStr.compareTo(passStr, false) ){
startActivity<MainActivity>()
}
Try this surely will work.
val style = buildString { karthik}
val style2 = buildString { karthik }
var result = style.equals(style2)
if(result){//Do something}