Kotlin - Readln() gets only first word in string - kotlin

I'm making a first project "Flashcards" for Kotlin course and faced with unexpected program behavior. Function "readln()" gets only first word in sting (separetad by space " "). What is a problem, what do you think?
Note: fun "reading" needed and for now I can realize it in this way only. Regular "readln()" have same problem.
Code below.
import java.util.*
var logText: String = ""
fun println(text: String = "") {
kotlin.io.println(text)
logText += text + "\n"
}
fun reading(): String {
val scan = Scanner(System.`in`)
val text = scan.next()
logText += text + "\n"
return text
}
fun adding(addCard: MutableMap<String, String>): MutableMap<String, String> {
val definition: String
println("The card:")
val card: String = reading()
if (card in addCard.keys) {
println("The card \"$card\" already exists.")
return addCard
} else {
println("The definition of the card:")
definition = reading()
if (definition in addCard.values) {
println("The definition \"$definition\" already exists.")
return addCard
}
}
addCard[card] = definition
println("The pair (\"${card}\":\"${definition}\") has been added.")
return addCard
}
fun main() {
val actionList = mutableListOf("add", "exit")
var action = ""
val cards = mutableMapOf<String, String>()
while (action != "exit") {
println("Input the action (add, remove, exit):")
action = reading()
if (action !in actionList) {
println("Wrong action!")
continue
} else {
when (action) {
"add" -> cards.putAll(adding(cards))
/* "remove" -> println("Not supported.")
"import" -> println("Not supported.")
"export" -> println("Not supported.")
"ask" -> println("Not supported.")
"log" -> println("Not supported.")
"hardest card" -> println("Not supported.")
"reset stats" -> println("Not supported.") */
}
}
}
println("Bye bye!")
}

You're not using readln() in your code, you're using a Scanner with the next() function and no delimiter set. So by default, that just splits on words:
import java.util.Scanner
fun main() {
val input = "here are some words"
val scanner = Scanner(input)
while(scanner.hasNext()) {
println(scanner.next())
}
}
here
are
some
words
If you use scanner.nextLine() then it'll read the whole line as a token, and that's basically the behaviour of readln() as well. If readln() is giving you individual words, you'll have to post the code that's doing that, because it'll be something else going on

Related

How to convert a function to listOf without lamdas?

There example of works code:
package cryptography
typealias taskFun = () -> Unit
var i: Int = 0
object tasks {
val supportTaskTextList = listOf("hide", "show", "exit")
val supportTaskFunList = listOf<taskFun>(fun() { println("hide $i");i++ }, fun() { println("show $i"); i++ } , fun() { println("Bye $i"); i++ })
fun hide() {
println("Hiding message in image.")
}
fun show() {
println("Obtaining message from image.")
}
fun exit() {
println("Bye!")
kotlin.system.exitProcess(0)
}
fun getTask() {
println("Task (${supportTaskTextList.joinToString(", ")}):")
val i = readln()
for (idx in supportTaskFunList.indices)
{
if (supportTaskTextList[idx] == i) return supportTaskFunList[idx]()
}
println("Wrong task: $i")
}
}
fun main() {
while(true) {
tasks.getTask()
}
}
Is code is works. But i want to call my methods without lamda. When i tried to just use them by name i got "main.kt:4:43: error: function invocation 'hide()' expected"
in: val supportTaskFunList = listOf<taskFun> = listOf(hide, show, exit)
Yet, i can to use it like:
package cryptography
typealias taskFun = () -> Unit
// var i: Int = 0
object tasks {
val hide = fun() {
println("Hiding message in image.")
}
val show = fun() {
println("Obtaining message from image.")
}
val exit = fun() {
println("Bye!")
kotlin.system.exitProcess(0)
}
val supportTaskTextList = listOf("hide", "show", "exit")
val supportTaskFunList = listOf<taskFun>(hide, show, exit)
fun getTask() {
println("Task (${supportTaskTextList.joinToString(", ")}):")
val i = readln()
for (idx in supportTaskFunList.indices)
{
if (supportTaskTextList[idx] == i) return supportTaskFunList[idx]()
}
println("Wrong task: $i")
}
}
fun main() {
while(true) {
tasks.getTask()
}
}
May i use it without lamdas? Just, like as in C++ though pointers on methods? And why i can't use functions without lamdas here?
The correct syntax to reference a function by name is not using a plain name, but the :: syntax, for which you still need the name of hte object task I think. You could try just writing ::hide, ::show... but I am not sure it resolves here.,
val supportTaskFunList = listOf(tasks::hide, tasks::show, tasks::exit)
Short mention: This is a function type. According to the documentation this is not a lambda (in Kotlin terminology) as it does not define a new function or use the lambda syntax, just references an existing function.

How should write the findViewById pass data to Fragment page from Activity page using kotlin

This is my activity page:
override fun receiveDetections(detections: Detector.Detections) {
val barcodes = detections.detectedItems
if (barcodes.size() == 1) {
scannedValue = barcodes.valueAt(0).rawValue
runOnUiThread {
cameraSource.stop()
toastText = scannedValue
Toast.makeText(this#InsertStockInActivity, toastText, Toast.LENGTH_SHORT).show()
val i = Intent(this#InsertStockInActivity, InputStockInActivity::class.java)
i.putExtra("key", toastText)
startActivity(i)
finish()
}
}else
{
Toast.makeText(this#InsertStockInActivity, "value- else", Toast.LENGTH_SHORT).show()
}
}
This is my Fragment Page, I using requireActivity().getIntent(), how can I show the "key" data?
val value = requireActivity().intent.getStringExtra("key") ?: ""
binding.edtId.findViewById<EditText>(R.id.value)
The binding.edtId.find.......... it got error, how should I write for this line ?

Kotlin - Evaluate functions from code string

General Question:
I would like to run in a kotlin app some code stored as String.
fun Evaluate(str: String,f:(s : String) -> Unit )
{
f(str)
}
For example, an Hello World
var function : String = "fun a(s:String) = println(s)"
Evaluate ("Hello World",function)
Is this possible, or maybe something close to this result ?
Specific Question :
I have an activity containing a layout and a map of variable :
private lateinit var glayout: LinearLayout
val variable : MutableMap<String, Any> = mutableMapOf(),
val code : List<String>
override fun onCreate(savedInstanceState: Bundle?) {
//Some init
glayout = binding.root.findViewById(R.id.gamelayout)
code = getCodeFromJson()
for (c in code){
//Here execute the code
}
}
So i would like to be able in my interpreted code to :
Modify a variable in the map
Instanciate any kind of views in the layout, from text to button with onClickListener
Run some specific android commands, like record, photo and others
I think the most reasonable way is to write a interpreter using your own language.
abstract class Interpreter {
fun run(sentence: String) {
val input = sentence.trim().split(" ")
val cmd = input[0]
val args = input.drop(1)
execute(cmd, args)
}
protected abstract fun execute(command: String, args: List<String>)
}
For example, if you have a map and you want the user to modify it:
class MapInterpreter(private val map: MutableMap<String, String>) : Interpreter() {
override protected fun execute(command: String, args: List<String>) {
when (command) {
"putmap" -> {
require(args.size == 2) { "usage: addmap [key] [value]" }
map[args[0]] = args[1]
}
"remmap" -> {
require(args.size == 1) { "usage: remmap [key]" }
map.remove(args[0])
}
"showmap" -> {
require(args.size == 0) { "usage: showmap" }
println(map)
}
}
}
}
To use it, just call the run method with the user input (from a text field, for example):
val map: MutableMap<String, String> = hashMapOf()
val interpreter = MapInterpreter(map)
interpreter.run("putmap I one")
interpreter.run("putmap V five")
interpreter.run("putmap X ten")
interpreter.run("putmap 2 two")
interpreter.run("showmap")
interpreter.run("remmap 2")
interpreter.run("showmap")
// Output:
// {2=two, V=five, X=ten, I=one}
// {V=five, X=ten, I=one}
Another example; to instantiate a Android View dynamically:
class ViewBuilderInterpreter(private val context: Context, private val parent: View) : Interpreter() {
override protected fun execute(command: String, args: List<String>) {
when (command) {
"textview" -> {
require(args.size >= 1 && args.size <= 2) { "usage: textview [text] {color}" }
parent.addView(Text(context).also {
it.text = args[0]
it.color = if (args.size == 1) Color.BLACK else Color.parseColor(args[1])
})
}
// ...
}
}
}
Of course that's just an idea, you also need to handle invalid commands and exceptions that might occur.

Kotlin read/import Map from txt.file

I am working on a learning project, that is supposed to import and export Flashcards to a txt.file which is later supposed to be used in questioning.
Currently, I am stuck on the import part and the research I did is not really working, because I am not really getting it.
I have this overall map where I save the term: definition in a map
private var flashCardMap = mutableMapOf<String, String>()
Then I have this export function
private fun export() {
println("File name:")
scan.nextLine()
val fileName = scan.nextLine()
val myFile = File(fileName)
try {
myFile.bufferedWriter().use { out->
flashCardMap.forEach {
out.write("${it.key}:${it.value}\n")
} }
println("${flashCardMap.size} cards have been saved.")
} catch (e: FileNotFoundException) {
println("File not Found.")
}
}
which exports all the cards I defined earlier in a txt. file like this with one or more Flashcard (Card = Definition)
key:value
AND here is where I am stuck. I try to import a .txt file and the including map but it does not work. It Is supposed to import the map and tell me how many Cards where imported and the add them to my current flashcardmap with which I am working in this session. Here is what I tried:
private fun import() {
println("File name:")
scan.nextLine()
val fileName = scan.nextLine()
val myFile = File("$fileName")
try {
val importMap =
myFile.readLines().chunked(2) {
it[0] to it[1]
}.toMap()
println("${importMap.size} cards have been loaded.")
flashCardMap.putAll(importMap)
} catch (e: FileNotFoundException) {
println("File not Found.")
}
}
There's actually so many ways to serialize structured data to a file, but since your example uses the key:value format, separated by new-lines, we'll stick with that.
This class should suit your needs. But it's pretty simplistic, and lacks any sort of error handling.
class Serializer(private val filePath: Path, private val delimiter: String = ":") {
fun export(data: Map<String, String>) {
filePath.toFile().writer().use { writer ->
for ((key, value) in data) {
writer.write("$key$delimiter$value\n")
}
}
}
fun import(): Map<String, String> {
val data = mutableMapOf<String, String>()
filePath.toFile().reader().use { reader ->
reader.forEachLine { line ->
val (key, value) = line.split(delimiter)
data[key] = value
}
}
return data
}
}
If you want to leverage a mature format, then the built-in java.util.Properties class can make things even easier. The only gotcha is that it uses a = delimiter by default, but it's supposed to be able to read a : delimiter too.
class PropertiesSerializer(private val filePath: Path) {
fun export(data: Map<String, String>) {
val props = Properties()
for ((key, value) in data) {
props[key] = value
}
filePath.toFile().outputStream().use { stream ->
props.store(stream, null)
}
}
fun import(): Map<String, String> {
val props = Properties()
filePath.toFile().inputStream().use { stream ->
props.load(stream)
}
return props
.map { (key, value) -> key.toString() to value.toString() }
.toMap()
}
}

Idiomatic way of handling nullable or empty List in Kotlin

Say I have a variable activities of type List<Any>?. If the list is not null and not empty, I want to do something, otherwise I want to do something else. I came up with following solution:
when {
activities != null && !activities.empty -> doSomething
else -> doSomethingElse
}
Is there a more idiomatic way to do this in Kotlin?
For some simple actions you can use the safe call operator, assuming the action also respects not operating on an empty list (to handle your case of both null and empty:
myList?.forEach { ...only iterates if not null and not empty }
For other actions. you can write an extension function -- two variations depending on if you want to receive the list as this or as a parameter:
inline fun <E: Any, T: Collection<E>> T?.withNotNullNorEmpty(func: T.() -> Unit): Unit {
if (this != null && this.isNotEmpty()) {
with (this) { func() }
}
}
inline fun <E: Any, T: Collection<E>> T?.whenNotNullNorEmpty(func: (T) -> Unit): Unit {
if (this != null && this.isNotEmpty()) {
func(this)
}
}
Which you can use as:
fun foo() {
val something: List<String>? = makeListOrNot()
something.withNotNullNorEmpty {
// do anything I want, list is `this`
}
something.whenNotNullNorEmpty { myList ->
// do anything I want, list is `myList`
}
}
You can also do inverse function:
inline fun <E: Any, T: Collection<E>> T?.withNullOrEmpty(func: () -> Unit): Unit {
if (this == null || this.isEmpty()) {
func()
}
}
I would avoid chaining these because then you are replacing an if or when statement with something more wordy. And you are getting more into the realm that the alternatives I mention below provide, which is full branching for success/failure situations.
Note: these extensions were generalized to all descendants of Collections holding non null values. And work for more than just Lists.
Alternatives:
The Result library for Kotlin gives a nice way to handle your case of "do this, or that" based on response values. For Promises, you can find the same thing in the Kovenant library.
Both of these libraries give you manner for returning alternative results from a single function, and also for branching the code based on the results. They do require that you are controlling the provider of the "answer" that is acted upon.
These are good Kotlin alternatives to Optional and Maybe.
Exploring the extension Functions Further (and maybe too much)
This section is just to show that when you hit an issue like the question raised here, you can easily find many answers in Kotlin to make coding the way you want it to be. If the world isn't likeable, change the world. It isn't intended as a good or bad answer, but rather additional information.
If you like the extension functions and want to consider chaining them in an expression, I would probably change them as follows...
The withXyz flavours to return this and the whenXyz should return a new type allowing the whole collection to become some new one (maybe even unrelated to the original). Resulting in code like the following:
val BAD_PREFIX = "abc"
fun example(someList: List<String>?) {
someList?.filterNot { it.startsWith(BAD_PREFIX) }
?.sorted()
.withNotNullNorEmpty {
// do something with `this` list and return itself automatically
}
.whenNotNullNorEmpty { list ->
// do something to replace `list` with something new
listOf("x","y","z")
}
.whenNullOrEmpty {
// other code returning something new to replace the null or empty list
setOf("was","null","but","not","now")
}
}
Note: full code for this version is at the end of the post (1)
But you could also go a completely new direction with a custom "this otherwise that" mechanism:
fun foo(someList: List<String>?) {
someList.whenNullOrEmpty {
// other code
}
.otherwise { list ->
// do something with `list`
}
}
There are no limits, be creative and learn the power of extensions, try new ideas, and as you can see there are many variations to how people want to code these type of situations. The stdlib cannot support 8 variations of these type of methods without being confusing. But each development group can have extensions that match their coding style.
Note: full code for this version is at the end of the post (2)
Sample code 1: Here is the full code for the "chained" version:
inline fun <E: Any, T: Collection<E>> T?.withNotNullNorEmpty(func: T.() -> Unit): T? {
if (this != null && this.isNotEmpty()) {
with (this) { func() }
}
return this
}
inline fun <E: Any, T: Collection<E>, R: Any> T?.whenNotNullNorEmpty(func: (T) -> R?): R? {
if (this != null && this.isNotEmpty()) {
return func(this)
}
return null
}
inline fun <E: Any, T: Collection<E>> T?.withNullOrEmpty(func: () -> Unit): T? {
if (this == null || this.isEmpty()) {
func()
}
return this
}
inline fun <E: Any, T: Collection<E>, R: Any> T?.whenNullOrEmpty(func: () -> R?): R? {
if (this == null || this.isEmpty()) {
return func()
}
return null
}
Sample Code 2: Here is the full code for a "this otherwise that" library (with unit test):
inline fun <E : Any, T : Collection<E>> T?.withNotNullNorEmpty(func: T.() -> Unit): Otherwise {
return if (this != null && this.isNotEmpty()) {
with (this) { func() }
OtherwiseIgnore
} else {
OtherwiseInvoke
}
}
inline fun <E : Any, T : Collection<E>> T?.whenNotNullNorEmpty(func: (T) -> Unit): Otherwise {
return if (this != null && this.isNotEmpty()) {
func(this)
OtherwiseIgnore
} else {
OtherwiseInvoke
}
}
inline fun <E : Any, T : Collection<E>> T?.withNullOrEmpty(func: () -> Unit): OtherwiseWithValue<T> {
return if (this == null || this.isEmpty()) {
func()
OtherwiseWithValueIgnore<T>()
} else {
OtherwiseWithValueInvoke(this)
}
}
inline fun <E : Any, T : Collection<E>> T?.whenNullOrEmpty(func: () -> Unit): OtherwiseWhenValue<T> {
return if (this == null || this.isEmpty()) {
func()
OtherwiseWhenValueIgnore<T>()
} else {
OtherwiseWhenValueInvoke(this)
}
}
interface Otherwise {
fun otherwise(func: () -> Unit): Unit
}
object OtherwiseInvoke : Otherwise {
override fun otherwise(func: () -> Unit): Unit {
func()
}
}
object OtherwiseIgnore : Otherwise {
override fun otherwise(func: () -> Unit): Unit {
}
}
interface OtherwiseWithValue<T> {
fun otherwise(func: T.() -> Unit): Unit
}
class OtherwiseWithValueInvoke<T>(val value: T) : OtherwiseWithValue<T> {
override fun otherwise(func: T.() -> Unit): Unit {
with (value) { func() }
}
}
class OtherwiseWithValueIgnore<T> : OtherwiseWithValue<T> {
override fun otherwise(func: T.() -> Unit): Unit {
}
}
interface OtherwiseWhenValue<T> {
fun otherwise(func: (T) -> Unit): Unit
}
class OtherwiseWhenValueInvoke<T>(val value: T) : OtherwiseWhenValue<T> {
override fun otherwise(func: (T) -> Unit): Unit {
func(value)
}
}
class OtherwiseWhenValueIgnore<T> : OtherwiseWhenValue<T> {
override fun otherwise(func: (T) -> Unit): Unit {
}
}
class TestBrancher {
#Test fun testOne() {
// when NOT null or empty
emptyList<String>().whenNotNullNorEmpty { list ->
fail("should not branch here")
}.otherwise {
// sucess
}
nullList<String>().whenNotNullNorEmpty { list ->
fail("should not branch here")
}.otherwise {
// sucess
}
listOf("a", "b").whenNotNullNorEmpty { list ->
assertEquals(listOf("a", "b"), list)
}.otherwise {
fail("should not branch here")
}
// when YES null or empty
emptyList<String>().whenNullOrEmpty {
// sucess
}.otherwise { list ->
fail("should not branch here")
}
nullList<String>().whenNullOrEmpty {
// success
}.otherwise {
fail("should not branch here")
}
listOf("a", "b").whenNullOrEmpty {
fail("should not branch here")
}.otherwise { list ->
assertEquals(listOf("a", "b"), list)
}
// with NOT null or empty
emptyList<String>().withNotNullNorEmpty {
fail("should not branch here")
}.otherwise {
// sucess
}
nullList<String>().withNotNullNorEmpty {
fail("should not branch here")
}.otherwise {
// sucess
}
listOf("a", "b").withNotNullNorEmpty {
assertEquals(listOf("a", "b"), this)
}.otherwise {
fail("should not branch here")
}
// with YES null or empty
emptyList<String>().withNullOrEmpty {
// sucess
}.otherwise {
fail("should not branch here")
}
nullList<String>().withNullOrEmpty {
// success
}.otherwise {
fail("should not branch here")
}
listOf("a", "b").withNullOrEmpty {
fail("should not branch here")
}.otherwise {
assertEquals(listOf("a", "b"), this)
}
}
fun <T : Any> nullList(): List<T>? = null
}
UPDATE:
kotlin 1.3 provide isNullOrEmpty now!
https://twitter.com/kotlin/status/1050426794682306562
try this! very clear.
var array: List<String>? = null
if (array.orEmpty().isEmpty()) {
// empty
} else {
// not empty
}
More simplest way would be,
if(activities?.isNotEmpty() == true) doSomething() else doSomethingElse()
Because of the safe call on activities?, the return value is Boolean? which can either be true, false or null. In order to use this expression in an if, we need to explicitly check if it's true
In addition to the other answers, you can also use the safe-call operator in combination with the extension method isNotEmpty(). Because of the safe call, the return value is actually Boolean? which can either be true, false or null. To use the expression in an if or when clause, you'll need to explictly check if it's true:
when {
activities?.isNotEmpty() == true -> doSomething
else -> doSomethingElse
}
Alternative syntax using the elvis operator:
when {
activities?.isNotEmpty() ?: false -> doSomething
else -> doSomethingElse
}
Consider using ?.forEach if appropriate
activities?.forEach {
doSmth(it)
}
If you want exactly the behavior you described I think your variant reads better then anything else more concise I can think of. (Yet simple if should suffice)
The actual method to use in Kotlin 1.3 is isNullOrEmpty like what was mentioned in this answer: https://stackoverflow.com/a/48056456/2735286
Here is an example of its usage:
fun main(args: Array<String>) {
var array: MutableList<String>? = null
println(array.isNullOrEmpty()) // true
array = mutableListOf()
println(array.isNullOrEmpty()) // true
array = mutableListOf("a")
println(array.isNullOrEmpty()) // false
}
This example prints out:
true
true
false
Kotlin 1.3 has extension isNullOrEmpty. The brief answer is:
if (activities.isNullOrEmpty) doSomething
else doSomethingElse
Extension is defined as:
fun <T> Collection<T>?.isNullOrEmpty(): Boolean
Similar extension exists for String and Array.
In my case prices is a optional.I handle the case in the following way with orEmpty() which returns the given array or an empty array if the given array is null.
val safeArray = poi.prices.orEmpty()
if (!safeArray.isEmpty()) {
...
}
Firstly I wanted to advise to make extension function in addition to #mlatu's answer, which handles else condition
public inline fun Map.forEachElse(operation: (Map.Entry) -> Unit, elseBlock: () -> Unit): Unit {
if (!empty)
for (element in this) operation(element)
else
elseBlock()
}
But the usage is no so beautiful.
Actually you are looking for a Maybe monad