How to print ClosedRange in Kotlin - kotlin

I'm learning Kotlin , and I'm trying to undetstand Ranges
I created a range of String as follows
val alpha = "A".."Z"
I want to print this for that I wrote
for (item in alpha) println(item)
But it gives the error
Error:(13, 18) Kotlin: For-loop range must have an 'iterator()' method
Can anyone help, how to print this range?

Well you can't do it with Strings by default, since there's no iterator() for ClosedRange<String>, but Chars will work directly:
val r = 'A'..'Z'
r.forEach(::println)
It will be of type CharRange and provide the needed iterator().
To make your very special example work with Strings, you could define your own extension function and delegate to a Iterator<Char>:
operator fun ClosedRange<String>.iterator(): Iterator<String> {
val charIt = (start.toCharArray().first()..endInclusive.toCharArray().first()).iterator()
return object : Iterator<String> {
override fun hasNext() = charIt.hasNext()
override fun next(): String = charIt.nextChar().toString()
}
}
Now it works as you wished. But be aware that this does not make sense for most use cases with ranges of String.

val alpha = "A".."Z"
This is a plain range, which means it's an abstract representation of a contiguous subset within a total order. The only operation such an entity supports is answering the question "is this element within this range?", and it will be based purely on the contract of Comparable<T>.
In your case, consider a string like "THREAD". Does it belong to your range? It sorts higher than "A" but lower than "Z", so it does belong to it. But you probably didn't intend to iterate over it, or the infinity of all other strings belonging to your range.
What you considered as a given is actually a special case: iterable ranges. They are defined only on the three types representing integral types: IntRange, LongRange and CharRange. These are the types where the subset belonging to the range can actually be enumerated and iterated over.

I Loved The answers of #s1m0nw1 and #Marko Topolnik.
You can't really iterate over a ClosedRange<String>.
The literal may mislead us to think it's a ClosedRange<Char>
var range = "A".."C" // misleading literal
What you CAN do:
Just a small addition: is to map the characters to Strings
val r = ('A'..'Z').map { it.toString() }//.forEach(::println)
for (letter in r){
}

How to print this range?
I think the only way to print this range is
println(alpha)
And you'll get
A..Z
This is how to "print" this range.
You're trying to travel through a non-iterable range, this is invalid.
Like, you cannot for (i in File("a.txt")..File("Main.java")) println(i).

Can You Try This May Help You, I think you actually want 'A'..'Z' not "A".."Z"
var A = 'A'..'Z'
for(value in A){
println("$value")
}

Related

How do I replace letters with numbers using the replace function in kotlin inside a lambda expression

mood = "leet"
modifier = { message ->
val regex = """(L|e|t)""".toRegex()
//Clueless about what to do after this
}
THIS IS WHAT I CAME UP WITH SO FAR, THE QUESTION IN THE BOOK BIG NERD RANCH KOTLIN EDITION 2 SAYS "leet (or 1337): The narrator will speak in leetspeak, replacing letters with numbers and symbols that look similar. For example, ‘L’ becomes ‘1’; ‘E’ becomes ‘3’; ‘T’ becomes ‘7’. (Hint: Take a look at String’s replace function. There is a version that accepts a lambda as the second parameter.)"
This is the function they're telling you to look at, specifically this one:
inline fun CharSequence.replace(
regex: Regex,
noinline transform: (MatchResult) -> CharSequence
): String
Returns a new string obtained by replacing each substring of this char sequence that matches the given regular expression with the result of the given function transform that takes MatchResult and returns a string to be used as a replacement for that match.
So the lambda you provide is a function that takes a MatchResult
and does something with it, and returns a CharSequence (which can be a one-character long String). The replace function calls that lambda for every match that regex makes.
You get the general idea of what you're supposed to do? You have two parts here - the thing that identifies parts of the input string to process, and the thing that takes those matches and changes them into something else. The result is the original string with those changes made. So you need to come up with a regex and a transform that work together.
Nobody (probably) is going to tell you the answer because the point is figuring it out for yourself, but if you have any questions about things like regexes people will be happy to help you out! And speaking of, this site is extremely useful (I just used it myself to check I knew what I was doing): https://regex101.com/
Here is the implementation as pointed by #cactustictacs :
5 -> {
mood = "leet"
val regex: Regex = """[LET]""".toRegex()
modifier = { message ->
message.uppercase().replace(regex) { m ->
when (m.value) {
"L" -> "1"
"E" -> "3"
"T" -> "7"
else -> ""
}
}
}
}
and here is the another method almost same but with minor change using regex.replace()
5 -> {
mood = "leet"
val regex: Regex = """[LET]""".toRegex()
modifier = { message ->
regex.replace(message.uppercase()){m ->
when (m.value) {
"L" -> "1"
"E" -> "3"
"T" -> "7"
else -> ""
}
}
}
}
You can use it in place of m to make it slightly more concise.

Counting how many times specific character appears in string - Kotlin

How one may count how many times specific character appears in string in Kotlin?
From looking at https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/ there is nothing built-in and one needs to write loop every time (or may own extension function), but maybe I missed a better way to achieve this?
Easy with filter {} function
val str = "123 123 333"
val countOfSymbol = str
.filter { it == '3' } // 3 is your specific character
.length
println(countOfSymbol) // output 5
Another approach
val countOfSymbol = str.count { it == '3'} // 3 is your specific character
println(countOfSymbol) // output 5
From the point of view of saving computer resources, the count decision(second approach) is more correct.

How to properly slice just the integers from a list?

I'm trying to average the grades from the input below. How do I slice out the name and just pass the integers to my calcAvg function? The grades are of variable length so my guess is I need to somehow slice my collection from element 1 to the size of the list?
input: Jack:90,80,70,90,50 Jill:80,100,30 Mary:20,100,90,80
fun main(){
print("Enter your grades: ")
val studentGrades = mutableListOf<String>()
while (true){
val input = readLine()!!
if (input.isNullOrBlank()) break
else
studentGrades += input
}
for (i in studentGrades){
val splitRecords = i.split(" ")
for (j in splitRecords){
val splitName = j.split(":", ",")//split the name from the grades
}
}
}
fun calcAvg(list: List<Double>): Double{
return list.average()
}
You're almost there, I think.
After splitting out individual records*, I'd split on just ":" to separate the name from the grades list.  That should give you a list of two items: the name, and the grades list, so you can treat those separately.  A naive way would be:
val nameAndGradesList = j.split(":")
val name = nameAndGrades[0]
val gradesList = nameAndGrades[1]
But there's a simpler way of doing that, using a destructuring declaration:
val (name, gradesList) = j.split(":")
Then you can separate the grades list into individual grades, and convert them to numbers:
val grades = gradesList.split(",").map{ it.toDouble() }
I guess you can take it from there…
Note that all this code assumes every record is in the right format; if not, it's liable to do strange things (e.g. crash by throwing an exception, or — even worse — give wrong results).  In production code, you'd usually want to check for that, and handle invalid records in an appropriate and predictable way.
(* You wouldn't need the first split if each record were on a separate line, which is the usual way.)

How to properly iterate over arrays in kotlin

I am currently learning kotlin and therefore following the kotlin track on exercism. The following exercise required me to calculate the Hamming difference between two Strings (so basically just counting the number of differences).
I got to the solution with the following code:
object Hamming {
fun compute(dnaOne: String, dnaTwo: String): Int {
if (dnaOne.length != dnaTwo.length) throw IllegalArgumentException("left and right strands must be of equal length.")
var counter = 0
for ((index, letter) in dnaOne.toCharArray().withIndex()) {
if (letter != dnaTwo.toCharArray()[index]) {
counter++
}
}
return counter
}
}
however, in the beginning I tried to do dnaOne.split("").withIndex() instead of dnaOne.toCharArray().withIndex() which did not work, it would literally stop after the first iteration and the following example
Hamming.compute("GGACGGATTCTG", "AGGACGGATTCT") would return 1 instead of the correct integer 9 (which only gets returned when using toCharArray)
I would appreciate any explanation
I was able to simplify this by using the built-in CharSequence.zip function because StringimplementsCharSequence` in Kotlin.
According to the documentation for zip:
Returns a list of pairs built from the characters of this and the [other] char sequences with the same index
The returned list has length of the shortest char sequence.
Which means we will get a List<Pair<Char,Char>> back (a list of pairs of letters in the same positions). Now that we have this, we can use Iterable.count to determine how many of them are different.
I implemented this as an extension function on String rather than in an object:
fun String.hamming(other: String): Int =
if(this.length != other.length) {
throw IllegalArgumentException("String lengths must match")
} else {
this.zip(other).count { it.first != it.second }
}
This also becomes a single expression now.
And to call this:
val ham = "GGACGGATTCTG".hamming("AGGACGGATTCT")
println("Hamming distance: $ham")

Smart cast of map access proven with `when in`

I’m trying to use Kotlin’s when block to look up an element in different maps. After confirming the element exists, the code subsequently does not smart-cast the resulting lookup in the map to not null.
Below is a minimum working example: is it possible to rework it such that !! is not needed?
fun main(args: Array<String>) {
val string = "abc"
val map1 = mapOf('a' to 5)
val map2 = mapOf('b' to 4)
when (val char = string.firstOrNull()) {
null -> println("Nothing to find")
in map1 -> println("Found in map1: ${map1[char]!!+1}")
in map2 -> println("Found in map2: ${map2[char]!!-1}")
else -> println("Unrecognised character $char")
}
}
Unfortunately, in Kotlin, functions can't have contracts of the form "if f returns true, then g doesn't return null." Hence, the compiler doesn't use information about definitely successful contains calls.
The workaround with !! is OK in this case because you can be sure that get returns not null. Implementation of complex patterns in when (KT-186) would cover this use case by allowing declaring a variable inside when clauses and providing static guarantees that it's not null.