Kotlin (if else) - kotlin

I'm new to kotlin. I need to make a calculator using enam. At the end of the code, there is a function that reads the action and returns the enam. The function works but, "if else" doesn't. Need console calculator, not in android studio.Please help!
All code from file
import java.lang.Exception
fun main() {
print("first number: ")
val first : Int = readNumber()
print("second number: ")
val second : Int = readNumber()
println("Enter action: +, -, *, /")
val sum : Int = first + second
println("Answer: $sum ")
}
fun readNumber() :Int{
return try {
readLine()!!.toInt()
}
catch (e:Exception){
0
}
}
enum class Action(val symbol : String){
PLUS("+"),
MINUS("-"),
MULTIPLY("*"),
DIVIDE("/");
}
fun defineAct(){
val pls = Action.PLUS
val mns = Action.MINUS
val mlt = Action.MULTIPLY
val dvd = Action.DIVIDE
if (val = pls){
sum = pls + mns
println("Ответ: ${sum}")
else if (val - mns){
sum = pls - mns
}
}

Your are using val keyword inside if-else. You could change it accordingly your requirements. Hope it will solve your problem.

Related

Evaluating a string in kotlin

I wrote a code in kotlin for evaluating a given string from Divison to subtraction, it works but it gives the wrong answer, for example i got a string x in the first line which have answer -215.96666 whereas the answer from code is -237.366666 idk where the error is. i saw more people using stack for doing it, but i wanted to do this way for evaluating a string
var x : String = "5+4-10x20-40/30x20+34/20"
fun div(x: String): String {
val lis1 = x.split("-").toMutableList()
for (ele1 in lis1) {
if ("/" in ele1) {
val pos1 = lis1.indexOf(ele1)
val lis2 = ele1.split("+").toMutableList()
for (ele2 in lis2) {
if ("/" in ele2) {
val pos3 = lis2.indexOf(ele2)
val lis3 = ele2.split("x").toMutableList()
for (ele3 in lis3) {
if ("/" in ele3) {
val pos4 = lis3.indexOf(ele3)
val lis4 = ele3.split("/")
val div = (lis4[0].toDouble() / lis4[1].toDouble()).toString()
lis3[pos4] = div
}
}
lis2[pos3] = lis3.joinToString("x")
}
}
lis1[pos1] = lis2.joinToString("+")
}
}
return (lis1.joinToString("-"))
}
fun mul(x : String) : String{
val lis1 = x.split("-").toMutableList()
for (ele1 in lis1) {
if("x" in ele1){
val pos1 = lis1.indexOf(ele1)
val lis2 = ele1.split("+").toMutableList()
for(ele2 in lis2){
if("x" in ele2){
val pos2 = lis2.indexOf(ele2)
val lis3 = ele2.split("x")
val mul = (lis3[0].toDouble() * lis3[1].toDouble()).toString()
lis2[pos2] = mul
}
}
lis1[pos1] = lis2.joinToString("+")
}
}
return (lis1.joinToString("-"))
}
fun add(x : String): String {
val lis1 = x.split("-").toMutableList()
for(ele1 in lis1){
if("+" in ele1){
val pos1 = lis1.indexOf(ele1)
val lis2 = ele1.split("+")
val add = (lis2[0].toDouble() + lis2[1].toDouble()).toString()
lis1[pos1] = add
}
}
return (lis1.joinToString("-"))
}
fun sub(x : String) : String{
val lis1 = x.split("-").toMutableList()
var sub = 0.0
for(ele1 in lis1){
sub -= ele1.toDouble()
}
return (sub.toString())
}
fun eval(x: String): String {
val divanswer = div(x)
val mulanswer = mul(divanswer)
val addanswer = add(mulanswer)
return sub(addanswer)
}
fun main(args: Array<String>){
println(eval(x))
}
i wanted the answer as -215.96666 but the answer given by code is -237.366666
In the case of this specific input, there are two bugs involved.
First bug is related to the fact you first process + and then -, but in mathematics we should process them together, from left to right. As a result, your algorithm processes this: 1-1+1 (correct answer: 1) as: 1-(1+1) (answer: -1). Alternatively, I believe handling - first and then + should work properly.
Second bug is that in sub() you start from 0 and subtract even the first number, but the first number should be actually added or used as an initial value.
I believe after fixing these two bugs, it should provide a correct answer for this specific input, but there are probably more bugs like these. For example, you incorrectly handle chains of the same operator, you only care about the first pair, so 1+1+1 becomes 2 (and then it is turned to -2 due to earlier mentioned bug).
As a general advice, learn to use a debugger and analyze how your data changes while your code is processing it. Even if you simply print your intermediate results: divanswer, mulanswer and addanswer and then run them through Google for processing, you will notice there is a problem somewhere at the add() step. Then rinse and repeat until everything works correctly.
Thanks to #broot for spotting this, the problem was with the addition and subtraction part, now that i merged them into one and got the correct answers for strings i input, here is the full code corrected.
var x : String = "5+4-10x20-40/30x20+34/20"
fun div(x: String): String {
val lis1 = x.split("-").toMutableList()
for (ele1 in lis1) {
if ("/" in ele1) {
val pos1 = lis1.indexOf(ele1)
val lis2 = ele1.split("+").toMutableList()
for (ele2 in lis2) {
if ("/" in ele2) {
val pos3 = lis2.indexOf(ele2)
val lis3 = ele2.split("x").toMutableList()
for (ele3 in lis3) {
if ("/" in ele3) {
val pos4 = lis3.indexOf(ele3)
val lis4 = ele3.split("/")
val div = (lis4[0].toDouble() / lis4[1].toDouble()).toString()
lis3[pos4] = div
}
}
lis2[pos3] = lis3.joinToString("x")
}
}
lis1[pos1] = lis2.joinToString("+")
}
}
return (lis1.joinToString("-"))
}
fun mul(x : String) : String{
val lis1 = x.split("-").toMutableList()
for (ele1 in lis1) {
if("x" in ele1){
val pos1 = lis1.indexOf(ele1)
val lis2 = ele1.split("+").toMutableList()
for(ele2 in lis2){
if("x" in ele2){
val pos2 = lis2.indexOf(ele2)
val lis3 = ele2.split("x")
val mul = (lis3[0].toDouble() * lis3[1].toDouble()).toString()
lis2[pos2] = mul
}
}
lis1[pos1] = lis2.joinToString("+")
}
}
return (lis1.joinToString("-"))
}
fun final(x: String): Double {
val substr = StringBuffer()
var answer = 0.0
var opr = '+'
for(ele in x.indices){
var current = x[ele]
if(current in '0'..'9' || current == '.'){
substr.append(current)
}
if(current == '-' || current == '+'){
var operand = substr.toString().toDouble()
substr.setLength(0)
when (opr){
'+' -> answer += operand
'-' -> answer -= operand
}
opr = current
}
}
val num = substr.toString().toDouble()
when(opr){
'+' -> answer += num
'-' -> answer -= num
}
return answer
}
fun eval(x: String): Double {
val divanswer = div(x)
return final(mul(divanswer))
}
fun main(args: Array<String>){
println(eval(x))
}

Kotlin Creating List<List<Map<String, String>>>

I am trying to return List<List<Map<String, String>>> from a function in kotlin. I'm new to kotlin.
Edit1
Here's how I am attempting to to this
val a = mutableListOf(mutableListOf(mutableMapOf<String, String>()))
The problem with the above variable is, I am unable to figure out how to insert data into this variable. I tried with this:
val a = mutableListOf(mutableListOf(mutableMapOf<String, String>()))
val b = mutableListOf(mutableMapOf<String, String>())
val c = mutableMapOf<String, String>()
c.put("c", "n")
b.add(c)
a.add(b)
This is giving me:
[[{}], [{}, {c=n}]]
What I want is [[{c=n}]]
Can someone tell me how I can insert data into it?
The end goal I am trying to achieve is to store data in the form of List<List<Map<String, String>>>
EDIT 2
The function for which I am trying to write this dat structure:
fun processReport(file: Scanner): MutableList<List<Map<String, String>>> {
val result = mutableListOf<List<Map<String, String>>>()
val columnNames = file.nextLine().split(",")
while (file.hasNext()) {
val record = mutableListOf<Map<String, String>>()
val rowValues = file.nextLine()
.replace(",(?=[^\"]*\"[^\"]*(?:\"[^\"]*\"[^\"]*)*$)".toRegex(), "")
.split(",")
for (i in rowValues.indices) {
record.add(mapOf(columnNames[i] to rowValues[i]))
print(columnNames[i] + " : " + rowValues[i] + " ")
}
result.add(record)
}
return result
}
You don't need to use mutable data structures. You can define it like this:
fun main() {
val a = listOf(listOf(mapOf("c" to "n")))
println(a)
}
Output:
[[{c=n}]]
If you wanted to use mutable data structures and add the data later, you could do it like this:
fun main() {
val map = mutableMapOf<String, String>()
val innerList = mutableListOf<Map<String, String>>()
val outerList = mutableListOf<List<Map<String, String>>>()
map["c"] = "n"
innerList.add(map)
outerList.add(innerList)
println(outerList)
}
The output is the same, although the lists and maps are mutable.
In response to the 2nd edit. Ah, you're parsing a CSV. You shouldn't try to do that yourself, but you should use a library. Here's an example using Apache Commons CSV
fun processReport(file: File): List<List<Map<String, String>>> {
val parser = CSVParser.parse(file, Charset.defaultCharset(), CSVFormat.DEFAULT.withHeader())
return parser.records.map {
it.toMap().entries.map { (k, v) -> mapOf(k to v) }
}
}
For the following CSV:
foo,bar,baz
a,b,c
1,2,3
It produces:
[[{foo=a}, {bar=b}, {baz=c}], [{foo=1}, {bar=2}, {baz=3}]]
Note that you can simplify it further if you're happy returning a list of maps:
fun processReport(file: File): List<Map<String, String>> {
val parser = CSVParser.parse(file, Charset.defaultCharset(), CSVFormat.DEFAULT.withHeader())
return parser.records.map { it.toMap() }
}
Output:
[{foo=a, bar=b, baz=c}, {foo=1, bar=2, baz=3}]
I'm using Charset.defaultCharset() here, but you should change it to whatever character set the CSV is in.

Kotlin: Type inference failed. Expected type mismatch: inferred type is Pair<String, Int> but Pair<Product, Int> was expected

I wanna call run the following function addToCart() in the main, but such error appears, may i know how should i change my code?
Thanks!
fun addToCart(){
println("Productname : ")
var nameInput= readLine() ?: "-"
println("Num of $nameInput ")
var num = readLine()!!.toInt()
var got : Product? = warehouse.getProductByName(nameInput)
shoppingCart.addToList(nameInput, num)
}
class ShoppingCart () {
private val productAndQuantityList = mutableListOf<Pair<Product, Int>>()
fun addToList(name: String, quantity: Int){
productAndQuantityList.add(Pair(name, quantity))
}
....
}
I think you need not null checks before calling add.
fun addProductToCart(shoppingCart: ShoppingCart, warehouse: Warehouse) {
println("Product name: ")
var productName_E = readLine() ?: "-"
println("No. of $productName_E ")
var num = readLine()?.toInt()
var got: Product? = warehouse.getProductByName(productName_E)
if (num != null && got != null) {
shoppingCart.productAndQuantityList.add(Pair(first = got, second = num))
}
}
Your ShoppingCart class should be something like the class below.
class ShoppingCart {
val productAndQuantityList = mutableListOf<kotlin.Pair<Product, Int>>()
...
}

Lambda expression inside Kotlin String

My code:
class Team (val name: String, val aggressive: Boolean = true) {
val attendance: Int
init {
if (aggressive){
attendance = 25000
} else {
attendance = 20000
}
}
}
...
fun chooseTeam() {
val homeTeam = Team(name = "Everton")
println("the home team is $homeTeam.aggressive so they are ${if ($homeTeam == "aggressive") "angry" else "timid" }")
}
I'm trying to assign the value of the lambda string based on if $homeTeam.aggressive is true or not.
However I'm getting red lines all over the lambda so obviously the syntax seems off. Can someone tell me whats wrong with the code?
What you actually mean is a string template and not a lambda. You must have confused it because both use curly brackets {...}.
You can either do it like this:
fun chooseTeam() {
val homeTeam = Team(name = "Everton")
// 1) no dollar sign before homeTeam in the comparison
// 2) you need to compare to homeTeam.aggressive and not homeTeam
println("the home team is ${homeTeam.name} so they are ${if (homeTeam.aggressive) "angry" else "timid" }")
}
Or better, you assign the mapping (Boolean to String) to a variable first which increases the readability.
fun chooseTeam() {
val homeTeam = Team(name = "Everton")
val adjective = if (homeTeam.aggressive) "angry" else "timid"
println("the home team is ${homeTeam.name} so they are $adjective")
}
The correct way
fun chooseTeam() {
val homeTeam = Team(name = "Everton")
// 1) no dollar sign before homeTeam in the comparison
// 2) in kotlin if you declare constructor parameter as val they also becomes property of class which you can access like this homeTeam.aggressive
// 2) if you want the name of team, just use ${homeTeam.name} instead $homeTeam.aggression
println("the home team is $homeTeam.aggression so they are ${if(homeTeam.aggressive) "angry" else "timid"}")
}
Hope this helps.
Edit :
More detailed explanation is given by #Willi Mentzel

Reading multiple ints from the same line in Kotlin?

I am doing the 30 Days of Code in Kotlin on Hackerrank and I am stuck at Day 7.
How do you read multiple integers on a single line?
How is it added to an array and displayed in reverse?
I have solved it in Java but lack the syntax needed in Kotlin
Input:
4
1 4 3 2
My Code:
fun main(args: Array<String>) {
val n = readLine()!!.toInt()
var arr = Array(n)
for(i in 0 until n)
{
arr[i] = readLine()!!.toInt() //Not Working? nor does readLine()!!.split(' ').toInt()
}
for(item in arr.size - 1 downTo 0)
{
print("${item} ")
}
}
EDIT: question was updated from the original
The problem is the readLine() will read the entire line from stdin, so each time you call readLine() in the for loop it will result in a separate line being read each time.
One approach to this is to read the line, and then to split and map each value to an Int.
readLine()?.let {
val numOfValues = it.toInt()
println(numOfValues)
readLine()?.let { line ->
line.split(" ").map {
it.toInt()
}.reversed().forEach {
println(it)
}
}
}
If you want to store them in a list then you can follow this method
var items = readLine()!!.trim().split("\\s+".toRegex()).map (String::toInt)
println(items)
You can also store them in different variables like this way
var (a,b) = readLine()!!.trim().split("\\s+".toRegex()).map (String::toInt)
println(a+b)
You can also use the following code to item items splited and stored in array for a beginner approach
fun main(ags :Array<String>)
{
var item = readLine()!!.trim()
println(item[0])
}
Actually, you can refer to the official Kotlin tutorial: https://kotlinlang.org/docs/tutorials/competitive-programming.html
as mentioned in tutorial:
To make reading the input in competitive programming tasks like this more concise, you can have the following list of helper input-reading functions:
private fun readLn() = readLine()!! // string line
private fun readInt() = readLn().toInt() // single int
private fun readStrings() = readLn().split(" ") // list of strings
private fun readInts() = readStrings().map { it.toInt() } // list of ints
for your case, you can try use as below:
fun main() {
val n = readInt()
val x = readInts()
for (j in x.reversed()) {
print(j); print(" ")
}
println()
}
private fun readLn() = readLine()!! // string line
private fun readInt() = readLn().toInt() // single int
private fun readStrings() = readLn().split(" ") // list of strings
private fun readInts() = readStrings().map { it.toInt() } // list of ints