How to use putextra () in Kotin - kotlin

I want to send data (number) from "edit text section" of Sub-Activity1 (users input a simple number)and receive in another Sub-activity2, and depending on the number I want to show different sets of text. I am a beginner and I am stuck where in Sub-Activity 2 as it returns error for val str where I want to receive and manipulate the number received from Sub-Activity 1 editText.
Sub-Activity 1 :
<Send & Open Sub-Activity2>
getResult.setOnClickListener {
val intent = Intent(this, subactivity::class.java)
val name: String = editTextID.getText().toString()
intent.putExtra(name:"editTextID",value:"7.0")
startActivity(intent)
This returns no error.
Sub-Activity 2: <Receive & Manipulate the text>
class subactivity2 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_subactivity2)
val str =intent.getStringExtra("editTextID")
when str == 7.0 {
infoTextView.textview.text= "textIwannaShow"
}
}

Franz might be right about you wanting to pass a Double, but since you're passing it as a String and also naming your val str, I'll assume you do want to pass a string (that just happens to represent a number). In which case you need to compare to a string
if (str == "7.0") {
infoTextView.textview.text = "textIwannaShow"
}
or if you do want a when block
when(str) {
"7.0" -> infoTextView.textview.text = "textIwannaShow"
}
If you actually want to work with numbers you'll have to call toDouble() on your string at some point to convert it to one. toDoubleOrNull would be better if you're taking that number from a text input (in case the user doesn't enter a valid number), but you're not actually using the value taken from the EditText

In your Sub-Activity 2, you are receiving a String not an Integer.
So, you should change your code from this
val str =intent.getStringExtra("editTextID")
To this
val str =intent.getIntExtra("editTextID", 0)
Anyway, in the example you are passing 7.0 which is Double, so you probably need this instead of above code
val str =intent.getDoubleExtra("editTextID", 0.0)

Related

Kotlin Generic problem, UNCHECKED_CAST , required:Nothing

#file:Suppress("UNCHECKED_CAST")
data class Element<T>(
val key: String,
val valueOne: T,
val valueTwo: T,
val comparator: Comparator<T>,
val comparatorValue: CompareResult
)
enum class CompareResult(
val value: Int
) {
LESS(-1),
EQUAL(0),
GREATER_THAN(1)
}
fun <T> matchesComparison(list:Collection<Element<T>>): Pair<Boolean, List<String>> {
val failedComparisons = mutableListOf<String>()
for (element in list) {
val compareValue = element.comparator.compare(element.valueOne, element.valueTwo)
if (element.comparatorValue.value != compareValue) {
failedComparisons.add(element.key)
}
}
return Pair(failedComparisons.isEmpty(), failedComparisons)
}
val stringComparator = Comparator.comparing(String::toString)
val intComparator = Comparator.comparing(Int::toInt)
val elementsToCompare = listOf(
Element("number", 1, 2, intComparator, CompareResult.LESS),
Element("first name", "a", "a", stringComparator, CompareResult.EQUAL),
Element("last name", "a", "b", stringComparator, CompareResult.EQUAL)
)
matchesComparison(elementsToCompare).second.joinToString(", ","Failed elements: \"","\"")
I often get faced with comparing two different object properties with the same values.
As an example object A has props number,firstname,lastname. What i want to do is create a list have and have a function which goes over these Elements and returns which props have failed the comparison. I've managed to use generics for both the object and the matchesComparison function which returns the failed comparisons. The problem begins when i want to pass this list which is of type Collection<Element<out Any>> to this function is i get a type missmatch. instead of using unchecked casts to force the Comparator to be of type Any i would like to do this
val stringComparator = Comparator.comparing(String::toString)
val intComparator = Comparator.comparing(Int::toInt)
The result value that of the script above should be Failed elements: "last name"
I tried changing the signature of the function to out any but then the comparator.compare method has both params as of type Nothing. I really want to avoid unsing unchecked casts.
matchesComparison() doesn't need to be generic in this case. It doesn't really care what is the type of the whole input collection, so we can simply use * here.
Then we have another problem. The compiler isn't smart enough to notice that while we perform operations on a single element, all its properties are of matching types. As a result, it doesn't allow to use element.comparator on element.valueOne and element.valueTwo. To fix this problem, we simply need to create a separate function which works on a single Element, so it understand the type for all properties is the same:
fun matchesComparison(list:Collection<Element<*>>): Pair<Boolean, List<String>> {
fun <T> Element<T>.matches() = comparatorValue.value == comparator.compare(valueOne, valueTwo)
val failedComparisons = mutableListOf<String>()
for (element in list) {
if (!element.matches()) {
failedComparisons.add(element.key)
}
}
return Pair(failedComparisons.isEmpty(), failedComparisons)
}
Also, I believe such matches() function should be actually a member function of Element. It seems strange that while Element is pretty independent and it contains everything that is needed to perform a comparison, it still requires to use external code for this. If it would have a matches() function then we wouldn't need to care about its T. matches() would work with any Element.

how to read mutliple lines of string into one variable using readln() in kotlin?

example:
a variable
val str = readln().replace("[^A-Za-z0-9 ] \\s+".toRegex(),"").trim()
should read multiple lines of input value, input value will be like this
heading
----------
topic1
topic2
or like this
heading
-------
a) topic1
b) topic2
input may contain special characters or tabs or spaces we need to remove them also
I don't know what your Regex is trying to do, but that's not really your question.
How do you know when the user has finished their input - a special word or an empty line?
Assuming an empty line, here's how you can get all the content
println("Enter something:")
var lines = ""
do {
val line = readLine()
lines += "${clean(line)}\n"
} while (!line.isNullOrBlank())
println("User input:\n$lines")
private fun clean(line: String?): String? {
return line?.replace("[^A-Za-z0-9 ] \\s+".toRegex(),"")?.trim()
}

Why am I geting a blank when I run this string funtion in Kotlin?

So I was solving a problem that required me to put unique characters in a string without using a data structure.
fun main(){
val s1 = "fhfnfnfjuw"
val s2 = "Osayuki"
val s3 = "Raymond"
val s4 = "Aseosa"
uniqueChar(s1)
}
fun uniqueChar(s: String){
val updatedString = ""
s.forEach {c ->
if (!updatedString.contains(c)){
updatedString.plus(c)
}
}
println(updatedString)
}
And getting this error
I'm not sure what's going on and why I'm getting a blank. I'm sure it's an easy fix, but I can't see it. Any help is appreciated.
updatedString.plus(c) does not change updatedString. It creates a new string, including the character c. Since you don't do anything with that, the new string goes...nowhere.
Instead, you probably wanted updatedString = updatedString.plus(c) -- or something better with StringBuilder, but that's the closest version to your code.

Unable to replace string inside a String in Kotlin

I am trying to replace a few sub strings inside a string. But my code doesn't seem to work.
val listOfMaleWords = listOf(" him", " he", " his")
val listOfFemaleWords = listOf(" her", " she", " her")
fun modifyIdeaForGender(rawIdea : String, desiredGender : String): String {
var theRawIdea = rawIdea
if (desiredGender == "FEMALE") {
println("desired gender is FEMALE")
listOfMaleWords.forEachIndexed { index, element ->
theRawIdea.replace(element, listOfFemaleWords[index])
}
} else {
println("desired gender is MALE")
listOfFemaleWords.forEachIndexed { index, element ->
theRawIdea.replace(element, listOfMaleWords[index])
}
}
return theRawIdea
}
fun main() {
var sampleString : String = "Tell him, he is special"
println(modifyIdeaForGender(sampleString, "FEMALE"))
}
Expected Output :
"Tell her, she is special"
Current Output :
"Tell him, he is special" // no change
Whats wrong with my code? The current output doesn't replace the string characters at all.
replace returns a new String that you are discarding immediately. It does not mutate theRawIdea itself, so you should assign it back to theRawIdea yourself. For example:
theRawIdea = theRawIdea.replace(element, listOfFemaleWords[index])
Though this would modify theRawIdea as you desire, it wouldn't replace the pronouns correctly. Once it replaces the "him"s with "her"s, it would try to replace the "he"s with "she"s. But note that "he" a substring of "her"! So this would produce:
Tell sher, she is special
This could be fixed by reordering the lists, putting the "he"-"she" pair first, or by using regex, adding \b word boundary anchors around the words:
// note that you should not have spaces before the words if you decide to use \b
val listOfMaleWords = listOf("him", "he", "his")
val listOfFemaleWords = listOf("her", "she", "her")
...
theRawIdea = theRawIdea.replace("\\b$element\\b".toRegex(), listOfFemaleWords[index])
Note that this doesn't account for capitalisation or the fact that changing from female gender pronouns to male ones is inherently broken. Your current code would change all her to him. It would require some more complicated natural language processing to accurately do this task in general.
Taking all that into account, I've rewritten your code with zip:
fun modifyMaleIdeaToFemaleGender(rawIdea : String): String {
var theRawIdea = rawIdea
// if you really want to do the broken female to male case, then this would be
// listOfFemaleWords zip listOfMaleWords
// and the loop below can stay the same
val zipped = listOfMaleWords zip listOfFemaleWords
zipped.forEach { (target, replacement) ->
theRawIdea = theRawIdea.replace("\\b$target\\b".toRegex(), replacement)
}
return theRawIdea
}
You can also use fold to avoid reassigning theRawIdea:
fun modifyIdeaToFemaleGender(rawIdea : String): String {
val zipped = listOfMaleWords zip listOfFemaleWords
return zipped.fold(rawIdea) { acc, (target, replacement) ->
acc.replace("\\b$target\\b".toRegex(), replacement)
}
}
Your code assumes that the replace() method performs an in-place mutation of the string. However, the string with the replaced values are returned by the replace(). So you need to change your code to contain something like:
theRawIdea = theRawIdea.replace(element, listOfFemaleWords[index])
To do this, you will have to use a conventional loop instead of listOfMaleWords.forEachIndexed style looping.

Kotlin string exists but can't use almost all string functionality

Summary: I have a string from which I can print and use substring, but can't use attributes such as length or functions such as .toInt() or .compareTo(), why would this be the case?
var s = "20"
val myToast = Toast.makeText(this, s, Toast.LENGTH_SHORT)
myToast.show()
//20
val myToast2 = Toast.makeText(this, s.length, Toast.LENGTH_SHORT)
myToast2.show()
//The app crashes with the error: android.content.res.Resources$NotFoundException: String resource ID #0x2
I can call substring on string s, but I can't call length, toInt(), compareTo(), etc.
The string clearly exists since I can print it and use substring but if that is true why does my app throw an error when I try to use other attributes and functions from it?
There are two overloads of Toast.makeText(). One accepts a String as the second argument, and displays that string. The other accepts an Int as the second argument, and displays whatever string resource has that integer id. (Normally you'd pass something like R.string.my_string here.)
When you call .length on your String, you'll get an Int back. And that means you wind up calling the second overload, which then looks for a string resource with the id 2. That doesn't exist, so you crash.
If you want to just display the number 2, then you need to make this a String again. You can use .toString() or "${s.length}", and so on.
Add .toString at the end of length,toInt(),compareTo(), etc. because s.length
return int :not String
Here is your modified answer
var s = "20"
val myToast = Toast.makeText(this, s, Toast.LENGTH_SHORT)
myToast.show()
//20
val myToast2 = Toast.makeText(this, s.length.toString(), Toast.LENGTH_SHORT)
myToast2.show()