How to replace sumBy with sumOf in kotlin 1.5 - kotlin

I have the following code:
val sum = list.itens.sumBy { item ->
when (item.intValueI == item.intValueII) {
true -> 1
else -> 0
}
}
Updating to Kotlin 1.5, I got the deprecated warning; How should I proceed to achieve the same functionality?
I tried below:
val result = list.itens.sumOf<ListItemClass> { item ->
val intValueI = item.value ?: 0
val intValueII = item.valueII ?: 0
when(item.intValueI == item.IntValueII){
true -> 1
else -> 0
}
}

Why not filter your items and count them instead of involving maths, since that seems like what you're after?
val sum = list.items.filter { it.intValue1 == it.intValue2 }.size
Or, even more simply (thanks Tenfour04 in comments!):
val sum = list.items.count { it.intValue1 == it.intValue2 }
If it's absolutely essential for some reason to use sumOf, a slightly hacky solution would be:
val sum = list.items.sumOf {
if (it.intValue2 == it.intValue2) 1 else 0 as Int
}
Looks like the compiler / Android Studio gets a bit confused when returning 1 & 0, hence needing an else of either it.intValue1 * 0 or 0 as Int. The former is messier, but the latter leaves a AS warning.

Related

Kotlin when change value

can i use when in Kotlin to change the value of an existing variable?
i understand this one:
val num = 1
val result = when {
num > 0 -> "positive"
num < 0 -> "negative"
else -> "zero"
}
println(result)
should be "positive"
but i want this( psuedo )....
val num = 1
var result = "init string"
//bunch of code here
// later....
result = when{
num > 0 -> "positive"
num < 0 -> "negative"
else -> "zero"
}
it writes positive, but it says "Variable "result" initializer is redundant.
What im missing here?
Thx
The line
var result = "init string"
is redundant because you leave no possibility of that value not getting overridden in the when statement. "init string" cannot be printed at the end of the code, the variable will always have one of the three possible values defined in the when.
But you can directly initialize result with the when statement:
fun main() {
var num = 1
// directly assign the result of the when statment to the variable
var result = when {
num > 0 -> "positive"
num < 0 -> "negative"
else -> "zero"
}
println(result)
}
This prints
positive
thank you for the answer.
But i can say....
fun main() {
var num = 1
// directly assign the result of the when statment to the variable
var result = when {
num > 0 -> "positive"
num < 0 -> "negative"
else -> "zero"
}
println(result)
// and then later reassign....
num = 2
result = when{
num == 2 -> "two"
else -> "not two"
{
println(result)
// prints two
}
So i cant reassign an existing string with a when statement, that is not initialized with an another when statement?
I hope this is readable. :)
Thank you.
dagogi

Can i check if condition is true for all elements in a list on Kotlin?

How can i check in if statement that condition is true for elements in a collection
fun main() {
var control = 20
val list = mutableListOf<Int>()
for (i in 1..20)
list.add(i)
while (true) {
control++
if (control % list[0] == 0 && control % list[1] == 0)
}
}
i only write 2 conditions for convenience
Not sure if you want to check if the condition is true for ALL the elements, or you just want to know which ONE in particular is true, or if ANY are true.
In the first scenario, where we want to know if ALL of them
val list = (1..20).toList() //a bit easier to create the list this way
val result = list.all { control % it == 0 }
println(result) //will print true if all of the elements are true, and false if at least one is false
The second scenario we can do a simple .map, to know each one individually.
val list = (1..20).toList()
val result = list.map { control % it == 0 }
println(result) //will print a list of type (true, false, true, etc) depending on each element
And if we want to check if ANY are true, we can do:
val list = (1..20).toList()
val result = list.any { control % it == 0 }
println(result) //will print true if any of the elements are true, and false if all of the elements are false
Edit since Todd mentioned none in the comments, I'll add a few other similar functions in case it would help others with similar questions.
Firstly, we don't actually need a list, all of these funcitons can work on the range directly (the ones above and the ones below)
val result = (1..20).all { it % 2 == 0 }
Other similar functions:
none - the opposite of all.
filter - will keep all elements for which the predicate is true.
filterNot - will keep all elements for which the predicate is false.
For example you can use filter:
fun main() {
val list = mutableListOf<Int>()
for (i in 1..20)
list.add(i)
list.filter { it % 2 === 1 }
.forEach { println(it) }
}
Change my code to this if anyone interested
fun main() {
var count = 20
var flag = false
val list = (1..20).toList()
while (true){
count++
if (list.all { count % it == 0 }){
println(count)
break
}
}
}

Kotlin idomatic way to get columns of connect four game when hovering over it

I want to realize a game of four . The new chip will hover under the mouse cursor and accoring to its x-coordinates I want to calculate the column over which it hovers atm (and where it will be inserted after a click)
At the moment I do sth like this:
fun whichColumnIsChip(chip : Chip) : Int{
val x = chip.x/2
val columnWidth = Chip.radius*2 + distanceBetweenColumns
val rightColumnBorder = IntArray(gamefield.columns.size){ i -> marginLeft+(i+1) * (Chip.radius*2 + distanceBetweenColumns) }
when {
x.betweenInclusive(0.0, rightColumnBorder[0].toDouble()) -> return 0
x.betweenInclusive(rightColumnBorder[0].toDouble(), rightColumnBorder[1].toDouble()) -> return 1
x.betweenInclusive(rightColumnBorder[1].toDouble(), rightColumnBorder[2].toDouble()) -> return 2
x.betweenInclusive(rightColumnBorder[2].toDouble(), rightColumnBorder[3].toDouble()) -> return 3
x.betweenInclusive(rightColumnBorder[3].toDouble(), rightColumnBorder[4].toDouble()) -> return 4
x.betweenInclusive(rightColumnBorder[4].toDouble(), rightColumnBorder[5].toDouble()) -> return 5
x.betweenInclusive(rightColumnBorder[5].toDouble(), rightColumnBorder[6].toDouble()) -> return 6
else -> return -10
}
}
So if my cursor hovers over in between the x-coordinates of the 3rd column I just want to return 3
The code above works as intended, but I am sure there is a much more idomatic and shorter way
Few improvements could be done
1) Since Kotlin's when is not only a statement but an expression as well, you can reduce this
when {
condition1 -> return 1
...
conditionN -> return N
}
to
return when {
condition1 -> 1
...
conditionN -> N
}
2) You can reduce copypaste by declaring a function that performs a check on given array and some index. In following example the function is declared as local in order to capture local variables x and rightColumnBorder, but it could be declared as regular or extension, it's up to you.
fun option1(): Int {
//...
val test = fun (i: Int) = x.betweenInclusive(
if (i > 0) rightColumnBorder[i - 1].toDouble() else 0.0,
rightColumnBorder[i].toDouble())
return when {
test(0) -> 0
test(1) -> 1
test(2) -> 2
test(3) -> 3
test(4) -> 4
test(5) -> 5
test(6) -> 6
else -> -10
}
}
However, in your particular case you can notice that returned result is determined by the given array index, so the whole when statement could be replaced with a loop:
fun option2(): Int {
//...
rightColumnBorder.forEachIndexed { idx, value ->
val from = if (idx > 0) rightColumnBorder[idx - 1].toDouble() else 0.0
if (x.betweenInclusive(from, value.toDouble())) {
return idx
}
}
return -10
}
OR
fun option3(): Int {
//...
val test = fun (i: Int) = x.betweenInclusive(
if (i > 0) rightColumnBorder[i - 1].toDouble() else 0.0,
rightColumnBorder[i].toDouble())
rightColumnBorder.forEachIndexed { i, _ -> if (test(i)) return i }
return -10
}

How and when does kotlin let run?

for all the examples on the internet i cant figure out when and how is kotlins let ran?
if(phones.size == 0){
phones.add("")
}
return phones[0]
so if phones list size is 0, we add empty string and return that instead.
Now how would one do same with let ?
phones.let {
return ""
}
does this work with size 0, or do i have to have null list?
do i need return keyword, if yes, where?
is the above fun always going to return empty string? or just when phones is null?
when is this let code block even ran?
Update:
val cakes = listOf("carrot", "cheese", "chocolate")
fun main(args: Array<String>) {
var cakesEaten = 0
while (cakesEaten < 3) { // 1
cakesEaten ++
val result = cakes?.let{
if(cakesEaten == 2) {
"HeyLo"
} else {
2
}
}
println("result value = $result")
when(result) {
is String -> println(" result variable is a String")
is Int -> println(" result variable is Integer")
}
}
}
result value = 2
result variable is Integer
result value = HeyLo
result variable is a String
result value = 2
result variable is Integer
Original post
If your 'phones' Object is a Nullable type,
val result = phones?.let{
// this block runs only if phones object is not null
// items can be accessed like it.size
// expression result will be returned. no need to mention return.
if(it.size == 0) {
it.add("")
it[0]
} else it.size
}
result value will be either it[0] or it.size and its type will be Any.
But if this the functionality you need you can check Markos solution.
If you're interested in how to write your logic in Kotlin's FP idiom, it doesn't involve let at all:
phones.takeIf { it.isEmpty() }?.add("")
return phones[0]
However, I don't find this idiom better than what you started out with.

Kotlin: Variable 'result' must be initialized

The compiler is showing error Kotlin: Variable result must be initialized.
Here is the code.
fun main(args: Array<String>) {
print("Enter two numbers: ")
// nextDouble() reads the next double from the keyboard
var first= readLine()!!.toDouble()
var second = readLine()!!.toInt()
print("Enter an choice(1-4)): ")
val operator = readLine()!!.toInt()
var result: Double
when (operator) {
1 -> result = first + second
2 -> result = first - second
3 -> result = first * second
4 -> result = first / second
else -> {
println("Error.")
}
}
println("The result is :- " +result)
}
The problem is that when you read the value of result here:
println("The result is :- " +result)
result might not be initialized, because here:
var result: Double
when (operator) {
1 -> result = first + second
2 -> result = first - second
3 -> result = first * second
4 -> result = first / second
else -> {
println("Error.")
}
You are NOT assigning a value to result in the else branch. You have several options, one could be to make result nullable. For instance:
var result = when (operator) {
1 -> first + second
2 -> first - second
3 -> first * second
4 -> first / second
else -> null
}
if (result != null) {
println("The result is :- " + result)
} else {
println("Error.")
}
Notice that if the operator is not (1-4) the value of result will be null. Also, in your code you're printing "Error" and then again you're attempting to print the result.
To add something more, you could make the thing a bit nicer if you defined your operator with the when statement as a method reference:
print("Enter an choice(1-4)): ")
val operatorCode = readLine()!!.toInt()
val operator: ((Int) -> Double)? = when (operatorCode) {
1 -> first::plus
2 -> first::minus
3 -> first::times
4 -> first::div
else -> null
}
if (operator != null) {
val result = operator.invoke(second)
println("The result is :- " + result)
} else {
println("Error.")
}
As jrtapsell points out the main issue is that you declare result to be a Double but you since you don't cover every possible value in the when statement, you are accessing an un-initialized variable.
Another option, if you really operators other than 1-4 want it to be an error condition and don't want result to end up with a valid Double is to use Optionals.
fun main(args: Array<String>) {
print("Enter two numbers: ")
// nextDouble() reads the next double from the keyboard
var first= readLine()!!.toDouble()
var second = readLine()!!.toInt()
print("Enter an choice(1-4)): ")
val operator = readLine()!!.toInt()
var result: Double? = null
when (operator) {
1 -> result = first + second
2 -> result = first - second
3 -> result = first * second
4 -> result = first / second
else -> {
println("Error.")
}
}
// only print the result if not null
result?.let {
println("The result is :- " +result)
}
}
In this case result will be null if the operator is not one of 1-4.
What is the error message trying to tell you
Variable 'result' must be initialized.
This means there are paths through your code where you access result before you have given it a value.
This is a problem because it means you have probably missed off handling a condition.
How do you get through your code without setting result
If the user inputs 5 result is not set
How to fix
Either set result in the else branch, or give it a default value in the declaration