if else return in kotlin - kotlin

Error :
Kotlin: Type mismatch: inferred type is String but Unit was expected
code :
fun main() {
val a = 2
var data: String = if (a != 2) {
return "Hello"
} else {
return "World"
}
}

Your code should be like this
var data: String = if (a != 2) {
"Hello"
} else {
"World"
}
By using return you are returning from the main function which has the return type set to "Unit". If you want to display the text, you should then call println(data).
Fun fact, when used like this you can even ignore the "{}" and make it one line like this :
var data: String = if (a != 2) "Hello" else "World"

Related

incrementing hash map count in Kotlin

I have the function below. However, when I pass a string to it, I get the following error:
error: operator call corresponds to a dot-qualified call 'charCountMap.get(c).plus(1)' which is not allowed on a nullable receiver 'charCountMap.get(c)'. charCountMap.put(c, charCountMap.get(c) + 1)
private fun characterCount(inputString:String) {
val charCountMap = HashMap<Char, Int>()
val strArray = inputString.toCharArray()
for (c in strArray)
{
if (charCountMap.containsKey(c))
{
charCountMap.put(c, charCountMap.get(c) + 1)
}
else
{
charCountMap.put(c, 1)
}
}
}
The Kotlin Standard Library has groupingBy and eachCount for this purpose, you don't need to do any of this manually:
private fun characterCount(inputString:String) {
val charCountMap : Map<Char, Int> = inputString.groupingBy { it }.eachCount()
}
Note that I put the type on charCountMap for clarity, but it can be left off and inferred.
There is nice compute method in HashMap for this:
private fun characterCount(inputString:String) = hashMapOf<Char, Int>().also { charCountMap ->
inputString.forEach { charCountMap.compute(it) { _, v -> if (v == null) 1 else v + 1 } }
}
Both the other answers are correct. Todd's answer is right, you don't need to write a function for this. Just use the standard library. And if you are going to write a function that updates maps, Михаил Нафталь's suggestion to use compute() to handle updating existing values is also good.
However, if you're just doing this an an exercise, here are three suggestions to fix/improve your algorithm:
Instead of get(), use getValue(), which does not return null. It will raise an exception if the element does not exist, but you already checked for that.
Use the [] operator instead of put() (no need to, it's just nicer syntax).
You don't need to call toCharArray() because Strings are already iterable.
if (charCountMap.containsKey(c))
{
charCountMap[c] = charCountMap.getValue(c) + 1
}
else
{
charCountMap[c] = 1
}
Rewriting the whole thing using standard formatting:
fun characterCount(inputString: String): Map<Char, Int> {
val charCountMap = mutableMapOf<Char, Int>()
for (c in inputString) {
if (charCountMap.containsKey(c)) {
charCountMap[c] = charCountMap.getValue(c) + 1
} else {
charCountMap[c] = 1
}
}
return charCountMap
}

How to change the characters in a string in kotlin

I am trying to change the character in a string to some other character.
Here is my code
fun main(args: Array<String>) {
var str: String = "H...H"
for(i in 0..str.length-1) {
if( str[i] == '.')
str[i] = 'B'
}
println(ans)
}
But this produces the error:
jdoodle.kt:20:16: error: no set method providing array access
str[i] = 'B'
But the following code works fine:
fun main(args: Array<String>) {
var str: String = "H...H"
var ans : String = ""
for(i in 0..str.length-1) {
if( str[i] == 'H')
ans += str[i]
else if( str[i] == '.')
ans += 'B'
}
println(ans)
}
I just want to change all the ..... in the string to B.
Like "H...H" to "HBBBH"
Why is the first code not working?
The first example does not work because Strings in kotlin are immutable and you cannot change characters. Instead, you have to create a new String, like your second example (which, in fact, creates a new String for each time through the loop).
Kotlin has a replace function for you:
fun main() {
val input = "H...H"
val output = input.replace('.', 'B')
println(output) // Prints "HBBBH"
}

Check if a string contains only letters

How I can make a function that take a string and return the result whether the string contain alphabet letter only or not.
function all returns true if all characters match the given predicate.
fun String.onlyLetters() = all { it.isLetter() }
if (str.onlyLetters()) {
// only letters
}
else {
}
You can use the function firstOrNull() to search for the 1st non letter char and compare the result with null:
fun onlyLetters(s: String): Boolean = (s.firstOrNull { !it.isLetter() } == null)
or as an extension function:
fun String.onlyLetters(): Boolean = (firstOrNull { !it.isLetter() } == null)
Note that this way you will get true even if the string is empty.
If you don't want this then you should add another condition for the length like:
fun String.onlyLetters(): Boolean = length > 0 && (firstOrNull { !it.isLetter() } == null)
You could use a simple regular expression to validate the input:
fun isOnlyLetters(word: String): Boolean {
val regex = "^[A-Za-z]*$".toRegex()
return regex.matches(word)}
Alternatively,
making the regex ^[A-Za-z ]*$ (space after "z")would allow any amount of whitespace (such as in a phrase) at any point in the string (i.e. and still return true).
making the regex ^[A-Za-z ]+$ (* -> +) would return false for an empty string(i.e. ensure that there is at least one character in the input, be it a letter or space).
create an extension function isLettersOnly()
/*
* This fuction return true only if the string contain a-z or A-Z,
* Otherwise false*/
fun String.isLettersOnly(): Boolean {
val len = this.length
for (i in 0 until len) {
if (!this[i].isLetter()) {
return false
}
}
return true
}
1.check a string value
fun main() {
val text = "name"
if (text.isLettersOnly()) {
println("This is contain a-z,A-Z only")
} else {
println("This contain something else")
}
}
output:
This is contain a-z,A-Z only
2.check a string value
fun main() {
val text = "name 5"
if (text.isLettersOnly()) {
println("This is contain a-z,A-Z only")
} else {
println("This contain something else")
}
}
output:
This contain something else

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.

Mutate string from an extension

I was trying to port a Swift script to Kotlin but it's not working as expected, what the code does is to consume a string while the condition is true (need it for a parser). In Swift it works as expected but in Kotlin it doesn't (I just started with Kotlin a month ago so maybe I'm missing something).
Swift
extension String {
#discardableResult public mutating func consumeWhile(test: (String) -> Bool) -> String {
var chars = [Character](self.characters)
var result = ""
while chars.count > 0 && test(String(chars[0])) {
result.append(chars.remove(at: 0))
}
self = String(chars)
return result
}
}
Kotlin
fun String.consumeWhile(test: (String) -> Boolean): String {
if (isEmpty()) return ""
val chars = toCharArray().toMutableList()
var result = ""
var i = -1
while (chars.isNotEmpty() && test(chars.first().toString())) {
result += chars.removeAt(0)
++i
}
removeRange(0..i)
return result
}
So the basic usage will look like
val myString = "--Test" // IntelliJ suggests change var to val
val consumedString = myString.consumeWhile{ it != "-" }
println("result: $myString consumedString: $consumedString")
// expected: "result: Test consumedString: --"
// but got: "result: --Test consumedString: --"
Edit: Thanks for all the answers, don't know if will be possible to do like I want because as mentioned string are immutable in Kotlin/Java (just using the same string).
I forgot to mention that I need the consumed string, basically b/c I'm doing a parser so I need to store the consumed chars and the mutated string. I will leave open this question but I ended up creating a class that implements only a few String class methods.
class Line(var string: String) {
val length: Int
get() = string.length
fun consumeWhile(test: (String) -> Boolean): String {
if (string.isEmpty()) return ""
val chars = string.toCharArray().toMutableList()
var result = ""
while (chars.isNotEmpty() && test(chars.first().toString())) {
result += chars.removeAt(0)
}
string = chars.joinToString("")
return result
}
fun isNullOrEmpty(): Boolean {
return string.isNullOrEmpty()
}
fun isNotEmpty(): Boolean {
return string.isNotEmpty()
}
private fun removeRange(range: IntRange) {
string = string.removeRange(range)
}
operator fun get(i: Int): Char {
return string[i]
}
}
Usage example
val line = Line(string)
if (line.isNotEmpty() && line[0].toString() == "(") {
line.consumeWhile { it == "(" }
while (line.isNotEmpty() && line[0].toString() != ")") {
line.consumeWhile { it == " " }
val key = line.consumeWhile { it != "=" }
line.consumeWhile { it == "\"" || it == "=" }
val value = line.consumeWhile { it != "\"" }
line.consumeWhile { it == "\"" }
attributes[key] = value
}
line.consumeWhile { it == ")" }
}
String is immutable in Kotlin & Java, so you can't modify its state anyway.
You should avoiding to makes the wheels repeatedly, there is an existing function String#dropWhile(Char) in Kotlin. one thing you need to do is invert the condition, for example:
val result = "--Test".dropWhile { it == '-' }
// ^--- "Test"
In both Java and Kotlin String is immutable and you cannot change it after it has been created.
In swift this presumably can be turned off through the mutating modifier. However in Kotlin removeRange(0..i) creates a new String object which you then discard.
To have it behave as you want you will need to either:
Create a wrapper object that contains a string that can be replaced.
Return both the split string and the rest as a Pair, you can then use the destructuring operators to assign it as [_, myString] = myString.consumeWhile {}
Kotlin Strings are immutable and cannot be modified in place. Instead you can create a new String and return it
fun String.consumeWhile(test: (String) -> Boolean): String {
if (isEmpty()) return ""
val chars = toCharArray().toMutableList()
while (chars.isNotEmpty() && test(chars.first().toString())) {
chars.removeAt(0)
// Do something with the char
}
return chars.joinToString(separator = "")
}
Additionally, unless I am misunderstanding, your test condition should be it == "-" to get the result you want:
val myString = "--Test"
val newString = myString.consumeWhile{ it == "-" }
println("result: $newString")
You use
myString.consumeWhile{ it != "-" }
which stops consuming as soon as it meets the first "-", and thus it's nothing more to do.
The code works as it should, if you use
myString.consumeWhile{ it == "-" }
you will get the expected output as is correct.
I ended up creating a class that implements only a few String class methods.
class Line(var string: String) {
val length: Int
get() = string.length
fun consumeWhile(test: (String) -> Boolean): String {
if (string.isEmpty()) return ""
val chars = string.toCharArray().toMutableList()
var result = ""
while (chars.isNotEmpty() && test(chars.first().toString())) {
result += chars.removeAt(0)
}
string = chars.joinToString("")
return result
}
fun isNullOrEmpty(): Boolean {
return string.isNullOrEmpty()
}
fun isNotEmpty(): Boolean {
return string.isNotEmpty()
}
private fun removeRange(range: IntRange) {
string = string.removeRange(range)
}
operator fun get(i: Int): Char {
return string[i]
}
}
Usage example
val line = Line(string)
if (line.isNotEmpty() && line[0].toString() == "(") {
line.consumeWhile { it == "(" }
while (line.isNotEmpty() && line[0].toString() != ")") {
line.consumeWhile { it == " " }
val key = line.consumeWhile { it != "=" }
line.consumeWhile { it == "\"" || it == "=" }
val value = line.consumeWhile { it != "\"" }
line.consumeWhile { it == "\"" }
attributes[key] = value
}
line.consumeWhile { it == ")" }
}
Obs: for now will mark as answered, till a better solution comes out